Compare commits
104 Commits
Author | SHA1 | Date | |
---|---|---|---|
60612cace9 | |||
f057502834 | |||
21a1149532 | |||
6724ca4f63 | |||
7a6c25b3fb | |||
0366e320af | |||
f03793b825 | |||
0907f030b4 | |||
7542e68b6f | |||
9003a34285 | |||
3cc27eaabe | |||
601b081bf3 | |||
4405d993c9 | |||
361308eb1b | |||
d894dedaf6 | |||
d12dd1491f | |||
1625591598 | |||
a50c30a4fd | |||
02bfc74c1e | |||
a012dd838d | |||
e2b634e59a | |||
80b98d8787 | |||
bf2ba83cd5 | |||
727c43dbab | |||
203dedfb3a | |||
8d5d4159a3 | |||
cecba0269f | |||
3c878793b5 | |||
0549f42030 | |||
50f248ec5b | |||
544bdb4fb1 | |||
88b295ff9f | |||
602326bb57 | |||
31857cf05f | |||
896d8e830c | |||
5f86e29830 | |||
579ae59eca | |||
90db743cc9 | |||
fe82897064 | |||
0f49f36519 | |||
a92b7342ba | |||
86818e9c52 | |||
7a8a00c705 | |||
c8d5e0a51c | |||
524a7ff6fb | |||
5f6ac33d59 | |||
b4f5e4206d | |||
5133c3e010 | |||
0b77ea422a | |||
5c1dd4ea18 | |||
e1c687184e | |||
297d1356a2 | |||
98327b0c13 | |||
6786aee5ed | |||
0b9c726b4e | |||
436dd6ee8c | |||
acc053302d | |||
534b371d42 | |||
6004e3d2e1 | |||
c632074ba7 | |||
664245d2a6 | |||
fda4fc674d | |||
bf28c24c82 | |||
32df0e80ca | |||
297eab738f | |||
5819dd3a5a | |||
a007b1bb2d | |||
5cb43b6bae | |||
f524138a64 | |||
0aa626b2fb | |||
3ae1050f67 | |||
67736642f3 | |||
09f3c87d20 | |||
9deca75de8 | |||
5bc1dede81 | |||
6d53d43766 | |||
325462d9bf | |||
ee4ae62946 | |||
153768ef7f | |||
7249a218ba | |||
de348a4c49 | |||
fda8ffd9ef | |||
6cb707cc4f | |||
998c5f17fc | |||
c34b357051 | |||
40f4e92461 | |||
c727da823b | |||
8d1b7962d8 | |||
a6dfe20348 | |||
ed46390bbc | |||
80eb5bf535 | |||
7596fdb460 | |||
8db1ff8aef | |||
1dfffdbc4e | |||
64b2b4a7d4 | |||
ae35d0e43c | |||
b22c5eb167 | |||
6d5e414863 | |||
3e74dfb66d | |||
1245628521 | |||
c567690004 | |||
2feff4207b | |||
8c40b6f9a7 | |||
fc759bff77 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -49,9 +49,11 @@ 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
|
||||
|
50
NEWS
50
NEWS
@ -1,4 +1,51 @@
|
||||
3.1.2
|
||||
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]
|
||||
@ -77,7 +124,6 @@ Translations:
|
||||
Matej Urbančič [sl], Krishnababu Krothapalli [te], Daniel Korostil [uk],
|
||||
Aron Xu [zh_CN]
|
||||
|
||||
|
||||
3.0.2
|
||||
=====
|
||||
* Network Menu [Dan Williams]
|
||||
|
12
configure.ac
12
configure.ac
@ -1,5 +1,5 @@
|
||||
AC_PREREQ(2.63)
|
||||
AC_INIT([gnome-shell],[3.1.3],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
|
||||
AC_INIT([gnome-shell],[3.1.4],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
|
||||
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_SRCDIR([src/shell-global.c])
|
||||
@ -64,16 +64,16 @@ fi
|
||||
|
||||
AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
|
||||
|
||||
CLUTTER_MIN_VERSION=1.5.15
|
||||
CLUTTER_MIN_VERSION=1.7.5
|
||||
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
|
||||
GJS_MIN_VERSION=0.7.11
|
||||
GJS_MIN_VERSION=1.29.15
|
||||
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.0
|
||||
TELEPATHY_GLIB_MIN_VERSION=0.15.3
|
||||
TELEPATHY_LOGGER_MIN_VERSION=0.2.4
|
||||
POLKIT_MIN_VERSION=0.100
|
||||
STARTUP_NOTIFICATION_MIN_VERSION=0.11
|
||||
@ -85,7 +85,7 @@ 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
|
||||
gdk-x11-3.0 libsoup-2.4
|
||||
clutter-x11-1.0 >= $CLUTTER_MIN_VERSION
|
||||
clutter-glx-1.0 >= $CLUTTER_MIN_VERSION
|
||||
libstartup-notification-1.0 >= $STARTUP_NOTIFICATION_MIN_VERSION
|
||||
@ -97,6 +97,8 @@ 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"])
|
||||
|
@ -264,7 +264,7 @@ StTooltip StLabel {
|
||||
}
|
||||
|
||||
.panel-corner:active,
|
||||
.panel-corner:checked,
|
||||
.panel-corner:overview,
|
||||
.panel-corner:focus {
|
||||
-panel-corner-inner-border-color: rgba(255,255,255,0.8);
|
||||
}
|
||||
@ -301,7 +301,7 @@ StTooltip StLabel {
|
||||
}
|
||||
|
||||
.panel-button:active,
|
||||
.panel-button:checked,
|
||||
.panel-button:overview,
|
||||
.panel-button:focus {
|
||||
border-image: url("panel-button-border.svg") 10 10 0 2;
|
||||
background-image: url("panel-button-highlight-wide.svg");
|
||||
@ -464,6 +464,7 @@ 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;
|
||||
@ -724,6 +725,8 @@ StTooltip StLabel {
|
||||
.lg-dialog StEntry
|
||||
{
|
||||
color: #88ff66;
|
||||
selection-background-color: #88ff66;
|
||||
selected-color: black;
|
||||
}
|
||||
|
||||
.lg-obj-inspector-title
|
||||
@ -1136,6 +1139,83 @@ 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;
|
||||
}
|
||||
@ -1195,6 +1275,8 @@ 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);
|
||||
}
|
||||
|
||||
@ -1261,6 +1343,16 @@ 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;
|
||||
@ -1476,6 +1568,8 @@ StTooltip StLabel {
|
||||
font-weight: bold;
|
||||
width: 23em;
|
||||
color: white;
|
||||
selection-background-color: white;
|
||||
selected-color: black;
|
||||
}
|
||||
|
||||
.run-dialog {
|
||||
@ -1579,6 +1673,90 @@ 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 */
|
||||
|
@ -10,11 +10,14 @@ 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 \
|
||||
@ -27,6 +30,7 @@ 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 \
|
||||
@ -35,6 +39,7 @@ 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 \
|
||||
|
53
js/misc/screenSaver.js
Normal file
53
js/misc/screenSaver.js
Normal file
@ -0,0 +1,53 @@
|
||||
/* -*- 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);
|
@ -14,7 +14,8 @@ const Tweener = imports.ui.tweener;
|
||||
|
||||
const POPUP_APPICON_SIZE = 96;
|
||||
const POPUP_SCROLL_TIME = 0.10; // seconds
|
||||
const POPUP_FADE_TIME = 0.1; // seconds
|
||||
const POPUP_FADE_IN_TIME = 0.4; // seconds
|
||||
const POPUP_FADE_OUT_TIME = 0.1; // seconds
|
||||
|
||||
const APP_ICON_HOVER_TIMEOUT = 200; // milliseconds
|
||||
|
||||
@ -74,7 +75,7 @@ AltTabPopup.prototype = {
|
||||
|
||||
_allocate: function (actor, box, flags) {
|
||||
let childBox = new Clutter.ActorBox();
|
||||
let primary = global.get_primary_monitor();
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
|
||||
let leftPadding = this.actor.get_theme_node().get_padding(St.Side.LEFT);
|
||||
let rightPadding = this.actor.get_theme_node().get_padding(St.Side.RIGHT);
|
||||
@ -119,7 +120,7 @@ AltTabPopup.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
show : function(backward, switch_group) {
|
||||
show : function(backward, binding) {
|
||||
let tracker = Shell.WindowTracker.get_default();
|
||||
let apps = tracker.get_running_apps ('');
|
||||
|
||||
@ -150,7 +151,7 @@ AltTabPopup.prototype = {
|
||||
this.actor.get_allocation_box();
|
||||
|
||||
// Make the initial selection
|
||||
if (switch_group) {
|
||||
if (binding == 'switch_group') {
|
||||
if (backward) {
|
||||
this._select(0, this._appIcons[0].cachedWindows.length - 1);
|
||||
} else {
|
||||
@ -159,6 +160,10 @@ 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) {
|
||||
@ -178,10 +183,15 @@ 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.
|
||||
Tweener.addTween(this.actor,
|
||||
{ opacity: 255,
|
||||
time: POPUP_FADE_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
time: POPUP_FADE_IN_TIME,
|
||||
transition: 'easeInOutExpo'
|
||||
});
|
||||
|
||||
return true;
|
||||
@ -221,8 +231,12 @@ AltTabPopup.prototype = {
|
||||
this.destroy();
|
||||
} else if (action == Meta.KeyBindingAction.SWITCH_GROUP) {
|
||||
this._select(this._currentApp, backwards ? this._previousWindow() : this._nextWindow());
|
||||
} else if (action == Meta.KeyBindingAction.SWITCH_GROUP_BACKWARD) {
|
||||
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)
|
||||
this._select(this._currentApp, this._previousWindow());
|
||||
@ -360,7 +374,7 @@ AltTabPopup.prototype = {
|
||||
if (this.actor.visible) {
|
||||
Tweener.addTween(this.actor,
|
||||
{ opacity: 0,
|
||||
time: POPUP_FADE_TIME,
|
||||
time: POPUP_FADE_OUT_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: Lang.bind(this,
|
||||
function() {
|
||||
@ -618,7 +632,7 @@ SwitcherList.prototype = {
|
||||
this._items[this._highlighted].add_style_pseudo_class('selected');
|
||||
}
|
||||
|
||||
let monitor = global.get_primary_monitor();
|
||||
let monitor = Main.layoutManager.primaryMonitor;
|
||||
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;
|
||||
@ -646,7 +660,7 @@ SwitcherList.prototype = {
|
||||
|
||||
_scrollToRight : function() {
|
||||
this._scrollableLeft = true;
|
||||
let monitor = global.get_primary_monitor();
|
||||
let monitor = Main.layoutManager.primaryMonitor;
|
||||
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;
|
||||
@ -743,7 +757,7 @@ SwitcherList.prototype = {
|
||||
let children = this._list.get_children();
|
||||
let childBox = new Clutter.ActorBox();
|
||||
|
||||
let primary = global.get_primary_monitor();
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
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)
|
||||
@ -873,7 +887,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 = global.get_primary_monitor();
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
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;
|
||||
|
@ -172,10 +172,12 @@ 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._filters.connect('scroll-event', Lang.bind(this, this._scrollFilter));
|
||||
|
||||
this._filtersBox = new St.ScrollView({ x_fill: false,
|
||||
y_fill: false,
|
||||
style_class: 'vfade' });
|
||||
this._filtersBox.add_actor(this._filters);
|
||||
this.actor.add(this._view.actor, { expand: true, x_fill: true, y_fill: true });
|
||||
this.actor.add(this._filters, { expand: false, y_fill: false, y_align: St.Align.START });
|
||||
this.actor.add(this._filtersBox, { 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,
|
||||
@ -193,14 +195,6 @@ 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;
|
||||
@ -333,8 +327,16 @@ 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);
|
||||
app.activate(params.workspace ? params.workspace.index() : -1);
|
||||
if (openNewWindow)
|
||||
app.open_new_window(workspace);
|
||||
else
|
||||
app.activate(workspace);
|
||||
},
|
||||
|
||||
dragActivateResult: function(id, params) {
|
||||
|
278
js/ui/automountManager.js
Normal file
278
js/ui/automountManager.js
Normal file
@ -0,0 +1,278 @@
|
||||
/* -*- 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;
|
||||
});
|
||||
}
|
||||
}
|
634
js/ui/autorunManager.js
Normal file
634
js/ui/autorunManager.js
Normal file
@ -0,0 +1,634 @@
|
||||
/* -*- 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;
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ 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;
|
||||
@ -329,7 +330,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 = global.get_primary_monitor();
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
let themeNode = this.actor.get_theme_node();
|
||||
let borderWidth = themeNode.get_length('-arrow-border-width');
|
||||
let arrowBase = themeNode.get_length('-arrow-base');
|
||||
|
@ -8,6 +8,7 @@ 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
|
||||
@ -35,8 +36,8 @@ Chrome.prototype = {
|
||||
|
||||
this._trackedActors = [];
|
||||
|
||||
global.screen.connect('monitors-changed',
|
||||
Lang.bind(this, this._monitorsChanged));
|
||||
Main.layoutManager.connect('monitors-changed',
|
||||
Lang.bind(this, this._relayout));
|
||||
global.screen.connect('restacked',
|
||||
Lang.bind(this, this._windowsRestacked));
|
||||
|
||||
@ -49,9 +50,15 @@ Chrome.prototype = {
|
||||
Main.overview.connect('hidden',
|
||||
Lang.bind(this, this._overviewHidden));
|
||||
|
||||
this._updateMonitors();
|
||||
this._updateFullscreen();
|
||||
this._queueUpdateRegions();
|
||||
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();
|
||||
},
|
||||
|
||||
_allocated: function(actor, box, flags) {
|
||||
@ -205,18 +212,18 @@ Chrome.prototype = {
|
||||
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;
|
||||
}
|
||||
_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();
|
||||
},
|
||||
|
||||
_findMonitorForRect: function(x, y, w, h) {
|
||||
@ -255,15 +262,6 @@ 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),
|
||||
@ -291,6 +289,11 @@ 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) {
|
||||
|
@ -153,14 +153,14 @@ CtrlAltTabPopup.prototype = {
|
||||
},
|
||||
|
||||
_getPreferredWidth: function (actor, forHeight, alloc) {
|
||||
let primary = global.get_primary_monitor();
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
|
||||
alloc.min_size = primary.width;
|
||||
alloc.natural_size = primary.width;
|
||||
},
|
||||
|
||||
_getPreferredHeight: function (actor, forWidth, alloc) {
|
||||
let primary = global.get_primary_monitor();
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
|
||||
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 = global.get_primary_monitor();
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
|
||||
let leftPadding = this.actor.get_theme_node().get_padding(St.Side.LEFT);
|
||||
let vPadding = this.actor.get_theme_node().get_vertical_padding();
|
||||
|
323
js/ui/layout.js
Normal file
323
js/ui/layout.js
Normal file
@ -0,0 +1,323 @@
|
||||
/* -*- 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;
|
||||
}
|
||||
};
|
@ -436,7 +436,7 @@ Inspector.prototype = {
|
||||
if (!this._eventHandler)
|
||||
return;
|
||||
|
||||
let primary = global.get_primary_monitor();
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
|
||||
let [minWidth, minHeight, natWidth, natHeight] =
|
||||
this._eventHandler.get_preferred_size();
|
||||
@ -907,7 +907,7 @@ LookingGlass.prototype = {
|
||||
},
|
||||
|
||||
_resizeTo: function(actor) {
|
||||
let primary = global.get_primary_monitor();
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
let myWidth = primary.width * 0.7;
|
||||
let myHeight = primary.height * 0.7;
|
||||
let [srcX, srcY] = actor.get_transformed_position();
|
||||
|
101
js/ui/main.js
101
js/ui/main.js
@ -12,6 +12,8 @@ const Meta = imports.gi.Meta;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const AutomountManager = imports.ui.automountManager;
|
||||
const AutorunManager = imports.ui.autorunManager;
|
||||
const Chrome = imports.ui.chrome;
|
||||
const CtrlAltTab = imports.ui.ctrlAltTab;
|
||||
const EndSessionDialog = imports.ui.endSessionDialog;
|
||||
@ -23,6 +25,7 @@ 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;
|
||||
@ -38,6 +41,8 @@ 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 = [];
|
||||
@ -59,6 +64,7 @@ let uiGroup = null;
|
||||
let magnifier = null;
|
||||
let xdndHandler = null;
|
||||
let statusIconDispatcher = null;
|
||||
let layoutManager = null;
|
||||
let _errorLogStack = [];
|
||||
let _startDate;
|
||||
let _defaultCssStylesheet = null;
|
||||
@ -126,6 +132,7 @@ 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();
|
||||
@ -139,7 +146,10 @@ 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);
|
||||
|
||||
@ -178,14 +188,9 @@ 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();
|
||||
|
||||
@ -300,14 +305,14 @@ function _windowRemoved(workspace, window) {
|
||||
function _windowLeftMonitor(metaScreen, monitorIndex, metaWin) {
|
||||
// If the window left the primary monitor, that
|
||||
// might make that workspace empty
|
||||
if (monitorIndex == global.get_primary_monitor_index())
|
||||
if (monitorIndex == layoutManager.primaryIndex)
|
||||
_queueCheckWorkspaces();
|
||||
}
|
||||
|
||||
function _windowEnteredMonitor(metaScreen, monitorIndex, metaWin) {
|
||||
// If the window entered the primary monitor, that
|
||||
// might make that workspace non-empty
|
||||
if (monitorIndex == global.get_primary_monitor_index())
|
||||
if (monitorIndex == layoutManager.primaryIndex)
|
||||
_queueCheckWorkspaces();
|
||||
}
|
||||
|
||||
@ -481,80 +486,16 @@ function _getAndClearErrorStack() {
|
||||
return errors;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -68,14 +68,19 @@ function _fixMarkup(text, allowMarkup) {
|
||||
// Support &, ", ', < and >, escape all other
|
||||
// occurrences of '&'.
|
||||
let _text = text.replace(/&(?!amp;|quot;|apos;|lt;|gt;)/g, '&');
|
||||
|
||||
// Support <b>, <i>, and <u>, escape anything else
|
||||
// so it displays as raw markup.
|
||||
return _text.replace(/<(\/?[^biu]>|[^>\/][^>])/g, '<$1');
|
||||
} else {
|
||||
// Escape everything
|
||||
let _text = text.replace(/&/g, '&');
|
||||
return _text.replace(/</g, '<');
|
||||
_text = _text.replace(/<(?!\/?[biu]>)/g, '<');
|
||||
|
||||
try {
|
||||
Pango.parse_markup(_text, -1, '');
|
||||
return _text;
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// !allowMarkup, or invalid markup
|
||||
return GLib.markup_escape_text(text, -1);
|
||||
}
|
||||
|
||||
function URLHighlighter(text, lineWrap, allowMarkup) {
|
||||
@ -880,16 +885,87 @@ 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;
|
||||
},
|
||||
@ -909,7 +985,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._iconBin;
|
||||
return this.actor;
|
||||
},
|
||||
|
||||
pushNotification: function(notification) {
|
||||
@ -928,7 +1004,11 @@ Source.prototype = {
|
||||
this.notifications.splice(index, 1);
|
||||
if (this.notifications.length == 0)
|
||||
this._lastNotificationRemoved();
|
||||
|
||||
this._updateCount();
|
||||
}));
|
||||
|
||||
this._updateCount();
|
||||
},
|
||||
|
||||
notify: function(notification) {
|
||||
@ -965,6 +1045,8 @@ 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
|
||||
@ -1257,7 +1339,7 @@ MessageTray.prototype = {
|
||||
Main.chrome.trackActor(this._notificationBin);
|
||||
Main.chrome.trackActor(this._summaryBoxPointer.actor);
|
||||
|
||||
global.screen.connect('monitors-changed', Lang.bind(this, this._setSizePosition));
|
||||
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._setSizePosition));
|
||||
|
||||
this._setSizePosition();
|
||||
|
||||
@ -1293,20 +1375,20 @@ MessageTray.prototype = {
|
||||
},
|
||||
|
||||
_setSizePosition: function() {
|
||||
let primary = global.get_primary_monitor();
|
||||
this.actor.x = primary.x;
|
||||
this.actor.y = primary.y + primary.height - 1;
|
||||
this.actor.width = primary.width;
|
||||
let monitor = Main.layoutManager.bottomMonitor;
|
||||
this.actor.x = monitor.x;
|
||||
this.actor.y = monitor.y + monitor.height - 1;
|
||||
this.actor.width = monitor.width;
|
||||
this._notificationBin.x = 0;
|
||||
this._notificationBin.width = primary.width;
|
||||
this._notificationBin.width = monitor.width;
|
||||
this._summaryBin.x = 0;
|
||||
this._summaryBin.width = primary.width;
|
||||
this._summaryBin.width = monitor.width;
|
||||
|
||||
if (this._pointerBarrier)
|
||||
global.destroy_pointer_barrier(this._pointerBarrier);
|
||||
this._pointerBarrier =
|
||||
global.create_pointer_barrier(primary.x + primary.width, primary.y + primary.height - this.actor.height,
|
||||
primary.x + primary.width, primary.y + primary.height,
|
||||
global.create_pointer_barrier(monitor.x + monitor.width, monitor.y + monitor.height - this.actor.height,
|
||||
monitor.x + monitor.width, monitor.y + monitor.height,
|
||||
4 /* BarrierNegativeX */);
|
||||
|
||||
|
||||
@ -1867,18 +1949,18 @@ MessageTray.prototype = {
|
||||
},
|
||||
|
||||
_showTray: function() {
|
||||
let primary = global.get_primary_monitor();
|
||||
let monitor = Main.layoutManager.bottomMonitor;
|
||||
this._tween(this.actor, '_trayState', State.SHOWN,
|
||||
{ y: primary.y + primary.height - this.actor.height,
|
||||
{ y: monitor.y + monitor.height - this.actor.height,
|
||||
time: ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
},
|
||||
|
||||
_hideTray: function() {
|
||||
let primary = global.get_primary_monitor();
|
||||
let monitor = Main.layoutManager.bottomMonitor;
|
||||
this._tween(this.actor, '_trayState', State.HIDDEN,
|
||||
{ y: primary.y + primary.height - 1,
|
||||
{ y: monitor.y + monitor.height - 1,
|
||||
time: ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
@ -2047,7 +2129,6 @@ 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,
|
||||
|
@ -149,7 +149,7 @@ ModalDialog.prototype = {
|
||||
},
|
||||
|
||||
_fadeOpen: function() {
|
||||
let monitor = global.get_focus_monitor();
|
||||
let monitor = Main.layoutManager.focusMonitor;
|
||||
|
||||
this._backgroundBin.set_position(monitor.x, monitor.y);
|
||||
this._backgroundBin.set_size(monitor.width, monitor.height);
|
||||
|
@ -122,7 +122,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, data.length, hasAlpha,
|
||||
return textureCache.load_from_raw(data, hasAlpha,
|
||||
width, height, rowStride, size);
|
||||
} else {
|
||||
let stockIcon;
|
||||
@ -148,7 +148,7 @@ NotificationDaemon.prototype = {
|
||||
//
|
||||
// Either a pid or ndata.notification is needed to retrieve or
|
||||
// create a source.
|
||||
_getSource: function(title, pid, ndata) {
|
||||
_getSource: function(title, pid, ndata, sender) {
|
||||
if (!pid && !(ndata && ndata.notification))
|
||||
return null;
|
||||
|
||||
@ -171,7 +171,7 @@ NotificationDaemon.prototype = {
|
||||
return source;
|
||||
}
|
||||
|
||||
let source = new Source(title, pid);
|
||||
let source = new Source(title, pid, sender);
|
||||
source.setTransient(isForTransientNotification);
|
||||
|
||||
if (!isForTransientNotification) {
|
||||
@ -190,9 +190,11 @@ NotificationDaemon.prototype = {
|
||||
actions, hints, timeout) {
|
||||
let id;
|
||||
|
||||
// Filter out chat and presence notifications from Empathy, since we
|
||||
// handle that information from telepathyClient.js
|
||||
// Filter out chat, presence, calls and invitation 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
|
||||
@ -244,7 +246,7 @@ NotificationDaemon.prototype = {
|
||||
let sender = DBus.getCurrentMessageContext().sender;
|
||||
let pid = this._senderToPid[sender];
|
||||
|
||||
let source = this._getSource(appName, pid, ndata);
|
||||
let source = this._getSource(appName, pid, ndata, sender);
|
||||
|
||||
if (source) {
|
||||
this._notifyForSource(source, ndata);
|
||||
@ -265,7 +267,7 @@ NotificationDaemon.prototype = {
|
||||
if (!ndata)
|
||||
return;
|
||||
|
||||
source = this._getSource(appName, pid, ndata);
|
||||
source = this._getSource(appName, pid, ndata, sender);
|
||||
|
||||
// We only store sender-pid entries for persistent sources.
|
||||
// Removing the entries once the source is destroyed
|
||||
@ -414,7 +416,7 @@ NotificationDaemon.prototype = {
|
||||
},
|
||||
|
||||
_onTrayIconAdded: function(o, icon) {
|
||||
let source = this._getSource(icon.title || icon.wm_class || _("Unknown"), icon.pid, null);
|
||||
let source = this._getSource(icon.title || icon.wm_class || _("Unknown"), icon.pid, null, null);
|
||||
source.setTrayIcon(icon);
|
||||
},
|
||||
|
||||
@ -427,18 +429,28 @@ NotificationDaemon.prototype = {
|
||||
|
||||
DBus.conformExport(NotificationDaemon.prototype, NotificationDaemonIface);
|
||||
|
||||
function Source(title, pid) {
|
||||
this._init(title, pid);
|
||||
function Source(title, pid, sender) {
|
||||
this._init(title, pid, sender);
|
||||
}
|
||||
|
||||
Source.prototype = {
|
||||
__proto__: MessageTray.Source.prototype,
|
||||
|
||||
_init: function(title, pid) {
|
||||
_init: function(title, pid, sender) {
|
||||
MessageTray.Source.prototype._init.call(this, title);
|
||||
|
||||
this._pid = pid;
|
||||
this._appStateChangedId = 0;
|
||||
if (sender)
|
||||
// TODO: dbus-glib implementation of watch_name() doesn’t 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._setApp();
|
||||
if (this.app)
|
||||
this.title = this.app.get_name();
|
||||
@ -447,6 +459,16 @@ 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();
|
||||
@ -499,10 +521,6 @@ 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) {
|
||||
@ -527,19 +545,6 @@ 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;
|
||||
@ -552,10 +557,6 @@ Source.prototype = {
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
if (this.app && this._appStateChangedId) {
|
||||
this.app.disconnect(this._appStateChangedId);
|
||||
this._appStateChangedId = 0;
|
||||
}
|
||||
MessageTray.Source.prototype.destroy.call(this);
|
||||
}
|
||||
};
|
||||
|
@ -121,7 +121,7 @@ Overview.prototype = {
|
||||
let spacing = node.get_length('spacing');
|
||||
if (spacing != this._spacing) {
|
||||
this._spacing = spacing;
|
||||
this.relayout();
|
||||
this._relayout();
|
||||
}
|
||||
}));
|
||||
|
||||
@ -202,6 +202,8 @@ 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() {
|
||||
@ -391,7 +393,7 @@ Overview.prototype = {
|
||||
[stageX, stageY] = event.get_coords();
|
||||
let dx = this._dragX - stageX;
|
||||
let dy = this._dragY - stageY;
|
||||
let primary = global.get_primary_monitor();
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
|
||||
this._dragX = stageX;
|
||||
this._dragY = stageY;
|
||||
@ -438,8 +440,13 @@ Overview.prototype = {
|
||||
return clone;
|
||||
},
|
||||
|
||||
relayout: function () {
|
||||
let primary = global.get_primary_monitor();
|
||||
_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;
|
||||
let rtl = (St.Widget.get_default_direction () == St.TextDirection.RTL);
|
||||
|
||||
let contentY = Main.panel.actor.height;
|
||||
|
432
js/ui/panel.js
432
js/ui/panel.js
@ -12,6 +12,7 @@ const Signals = imports.signals;
|
||||
|
||||
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;
|
||||
@ -24,8 +25,6 @@ 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;
|
||||
@ -544,13 +543,163 @@ 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);
|
||||
}
|
||||
|
||||
function PanelCorner(side) {
|
||||
this._init(side);
|
||||
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);
|
||||
}
|
||||
|
||||
PanelCorner.prototype = {
|
||||
_init: function(side) {
|
||||
_init: function(panel, side) {
|
||||
this._panel = panel;
|
||||
this._side = side;
|
||||
this.actor = new St.DrawingArea({ style_class: 'panel-corner' });
|
||||
this.actor.connect('repaint', Lang.bind(this, this._repaint));
|
||||
@ -626,185 +775,14 @@ PanelCorner.prototype = {
|
||||
this.actor.set_size(cornerRadius,
|
||||
innerBorderWidth + cornerRadius);
|
||||
if (this._side == St.Side.LEFT)
|
||||
this.actor.set_position(Main.panel.actor.x,
|
||||
Main.panel.actor.y + Main.panel.actor.height - innerBorderWidth);
|
||||
this.actor.set_position(this._panel.actor.x,
|
||||
this._panel.actor.y + this._panel.actor.height - innerBorderWidth);
|
||||
else
|
||||
this.actor.set_position(Main.panel.actor.x + Main.panel.actor.width - cornerRadius,
|
||||
Main.panel.actor.y + Main.panel.actor.height - innerBorderWidth);
|
||||
this.actor.set_position(this._panel.actor.x + this._panel.actor.width - cornerRadius,
|
||||
this._panel.actor.y + this._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, { 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();
|
||||
@ -834,8 +812,8 @@ Panel.prototype = {
|
||||
this._centerBox = new St.BoxLayout({ name: 'panelCenter' });
|
||||
this._rightBox = new St.BoxLayout({ name: 'panelRight' });
|
||||
|
||||
this._leftCorner = new PanelCorner(St.Side.LEFT);
|
||||
this._rightCorner = new PanelCorner(St.Side.RIGHT);
|
||||
this._leftCorner = new PanelCorner(this, St.Side.LEFT);
|
||||
this._rightCorner = new PanelCorner(this, St.Side.RIGHT);
|
||||
|
||||
/* This box container ensures that the centerBox is positioned in the *absolute*
|
||||
* center, but can be pushed aside if necessary. */
|
||||
@ -909,32 +887,16 @@ Panel.prototype = {
|
||||
}));
|
||||
|
||||
/* 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". */
|
||||
let label = new St.Label({ text: _("Activities") });
|
||||
this.button = new St.Button({ name: 'panelActivities',
|
||||
style_class: 'panel-button',
|
||||
reactive: true,
|
||||
can_focus: true });
|
||||
this._activities = this.button;
|
||||
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);
|
||||
this._activitiesButton = new ActivitiesButton();
|
||||
this._activities = this._activitiesButton.actor;
|
||||
this._leftBox.add(this._activities);
|
||||
|
||||
// Synchronize the buttons pseudo classes with its corner
|
||||
this.button.connect('style-changed', Lang.bind(this,
|
||||
// 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,
|
||||
function(actor) {
|
||||
let rtl = actor.get_direction() == St.TextDirection.RTL;
|
||||
let corner = rtl ? this._rightCorner : this._leftCorner;
|
||||
@ -942,8 +904,6 @@ Panel.prototype = {
|
||||
corner.actor.set_style_pseudo_class(pseudoClass);
|
||||
}));
|
||||
|
||||
this._hotCorner = null;
|
||||
|
||||
this._appMenu = new AppMenuButton();
|
||||
this._leftBox.add(this._appMenu.actor);
|
||||
|
||||
@ -982,28 +942,6 @@ Panel.prototype = {
|
||||
Main.statusIconDispatcher.connect('status-icon-added', Lang.bind(this, this._onTrayIconAdded));
|
||||
Main.statusIconDispatcher.connect('status-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
|
||||
|
||||
// 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);
|
||||
Main.chrome.addActor(this._leftCorner.actor, { affectsStruts: false,
|
||||
affectsInputRegion: false });
|
||||
@ -1012,33 +950,9 @@ Panel.prototype = {
|
||||
|
||||
Main.ctrlAltTabManager.addGroup(this.actor, _("Top Bar"), 'start-here',
|
||||
{ sortGroup: CtrlAltTab.SortGroup.TOP });
|
||||
},
|
||||
|
||||
_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;
|
||||
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._relayout));
|
||||
this._relayout();
|
||||
},
|
||||
|
||||
startStatusArea: function() {
|
||||
@ -1085,8 +999,8 @@ Panel.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
relayout: function() {
|
||||
let primary = global.get_primary_monitor();
|
||||
_relayout: function() {
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
|
||||
this.actor.set_position(primary.x, primary.y);
|
||||
this.actor.set_size(primary.width, -1);
|
||||
|
@ -35,7 +35,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 = global.get_primary_monitor();
|
||||
let monitor = Main.layoutManager.primaryMonitor;
|
||||
this.menu.actor.style = ('max-height: ' +
|
||||
Math.round(monitor.height - Main.panel.actor.height) +
|
||||
'px;');
|
||||
|
@ -711,7 +711,6 @@ PopupSwitchMenuItem.prototype = {
|
||||
this._statusLabel = new St.Label({ text: '',
|
||||
style_class: 'popup-inactive-menu-item'
|
||||
});
|
||||
this._switch = new Switch(false);
|
||||
this._statusBin.child = this._switch.actor;
|
||||
},
|
||||
|
||||
@ -947,6 +946,14 @@ 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++) {
|
||||
|
@ -333,33 +333,46 @@ __proto__: ModalDialog.ModalDialog.prototype,
|
||||
|
||||
if (GLib.file_test(path, GLib.FileTest.EXISTS)) {
|
||||
let file = Gio.file_new_for_path(path);
|
||||
Gio.app_info_launch_default_for_uri(file.get_uri(),
|
||||
global.create_app_launch_context());
|
||||
} else {
|
||||
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();
|
||||
})
|
||||
});
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
this._showError(e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_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();
|
||||
|
@ -3,10 +3,11 @@
|
||||
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
|
||||
@ -246,18 +247,14 @@ function _collect(scriptModule, outputFile) {
|
||||
Shell.write_string_to_stream(out, '"events":\n');
|
||||
Shell.PerfLog.get_default().dump_events(out);
|
||||
|
||||
let monitors = global.get_monitors();
|
||||
let primary = global.get_primary_monitor();
|
||||
let monitors = Main.layoutManager.monitors;
|
||||
let primary = Main.layoutManager.primaryIndex;
|
||||
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(is_primary ? "*" : "",
|
||||
Shell.write_string_to_stream(out, '"%s%dx%d+%d+%d"'.format(i == primary ? "*" : "",
|
||||
monitor.width, monitor.height,
|
||||
monitor.x, monitor.y));
|
||||
}
|
||||
|
405
js/ui/shellMountOperation.js
Normal file
405
js/ui/shellMountOperation.js
Normal file
@ -0,0 +1,405 @@
|
||||
/* -*- 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);
|
@ -1281,12 +1281,29 @@ NMDeviceWireless.prototype = {
|
||||
if (apObj.accessPoints.length == 0) {
|
||||
if (apObj.item)
|
||||
apObj.item.destroy();
|
||||
this._networks.splice(pos, 1);
|
||||
if (this._overflowItem &&
|
||||
this._overflowItem.menu.length == 0) {
|
||||
this._overflowItem.destroy();
|
||||
this._overflowItem = null;
|
||||
|
||||
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);
|
||||
|
||||
} else if (apObj.item)
|
||||
apObj.item.updateAccessPoints(apObj.accessPoints);
|
||||
},
|
||||
@ -1482,14 +1499,16 @@ NMDeviceWireless.prototype = {
|
||||
}
|
||||
}));
|
||||
}
|
||||
if (position < NUM_VISIBLE_NETWORKS)
|
||||
if (position < NUM_VISIBLE_NETWORKS) {
|
||||
apObj.isMore = false;
|
||||
this.section.addMenuItem(apObj.item, position);
|
||||
else {
|
||||
} 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;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -12,8 +12,8 @@ const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const Util = imports.misc.util;
|
||||
|
||||
const BUS_NAME = 'org.gnome.PowerManager';
|
||||
const OBJECT_PATH = '/org/gnome/PowerManager';
|
||||
const BUS_NAME = 'org.gnome.SettingsDaemon';
|
||||
const OBJECT_PATH = '/org/gnome/SettingsDaemon/Power';
|
||||
|
||||
const UPDeviceType = {
|
||||
UNKNOWN: 0,
|
||||
@ -41,7 +41,7 @@ const UPDeviceState = {
|
||||
};
|
||||
|
||||
const PowerManagerInterface = {
|
||||
name: 'org.gnome.PowerManager',
|
||||
name: 'org.gnome.SettingsDaemon.Power',
|
||||
methods: [
|
||||
{ name: 'GetDevices', inSignature: '', outSignature: 'a(susbut)' },
|
||||
{ name: 'GetPrimaryDevice', inSignature: '', outSignature: '(susbut)' },
|
||||
@ -93,7 +93,6 @@ 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();
|
||||
@ -145,7 +144,6 @@ Indicator.prototype = {
|
||||
this._deviceItems = [];
|
||||
|
||||
if (error) {
|
||||
this._checkError(error);
|
||||
this._deviceSep.actor.hide();
|
||||
return;
|
||||
}
|
||||
@ -176,21 +174,12 @@ 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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -14,24 +14,14 @@ 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: '' },
|
||||
{ name: 'SetActive', inSignature: 'b' }]
|
||||
};
|
||||
|
||||
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>.
|
||||
@ -63,7 +53,7 @@ StatusMenuButton.prototype = {
|
||||
this._account_mgr = Tp.AccountManager.dup()
|
||||
|
||||
this._upClient = new UPowerGlib.Client();
|
||||
this._screenSaverProxy = new ScreenSaverProxy(DBus.session, BUS_NAME, OBJECT_PATH);
|
||||
this._screenSaverProxy = new ScreenSaver.ScreenSaverProxy();
|
||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
|
||||
this._iconBox = new St.Bin();
|
||||
@ -301,8 +291,11 @@ StatusMenuButton.prototype = {
|
||||
|
||||
_onLoginScreenActivate: function() {
|
||||
Main.overview.hide();
|
||||
this._gdm.goto_login_session();
|
||||
this._onLockScreenActivate();
|
||||
// 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();
|
||||
}));
|
||||
},
|
||||
|
||||
_onQuitSessionActivate: function() {
|
||||
@ -315,6 +308,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._upClient.suspend_sync(null);
|
||||
}));
|
||||
|
@ -24,6 +24,9 @@ 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'
|
||||
@ -69,8 +72,9 @@ function Client() {
|
||||
|
||||
Client.prototype = {
|
||||
_init : function() {
|
||||
// channel path -> Source
|
||||
this._sources = {};
|
||||
// channel path -> ChatSource
|
||||
this._chatSources = {};
|
||||
this._chatState = Tp.ChannelChatState.ACTIVE;
|
||||
|
||||
// Set up a SimpleObserver, which will call _observeChannels whenever a
|
||||
// channel matching its filters is detected.
|
||||
@ -87,6 +91,11 @@ Client.prototype = {
|
||||
this._tpClient.set_handle_channels_func(
|
||||
Lang.bind(this, this._handleChannels));
|
||||
|
||||
// Allow other clients (such as Empathy) to pre-empt our channels if
|
||||
// needed
|
||||
this._tpClient.set_delegated_channels_callback(
|
||||
Lang.bind(this, this._delegatedChannelsCb));
|
||||
|
||||
try {
|
||||
this._tpClient.register();
|
||||
} catch (e) {
|
||||
@ -130,20 +139,20 @@ Client.prototype = {
|
||||
return;
|
||||
|
||||
/* We got the TpContact */
|
||||
this._createSource(account, conn, channel, contacts[0]);
|
||||
this._createChatSource(account, conn, channel, contacts[0]);
|
||||
}), null);
|
||||
}
|
||||
|
||||
context.accept();
|
||||
},
|
||||
|
||||
_createSource: function(account, conn, channel, contact) {
|
||||
if (this._sources[channel.get_object_path()])
|
||||
_createChatSource: function(account, conn, channel, contact) {
|
||||
if (this._chatSources[channel.get_object_path()])
|
||||
return;
|
||||
|
||||
let source = new Source(account, conn, channel, contact, this._tpClient);
|
||||
let source = new ChatSource(account, conn, channel, contact, this._tpClient);
|
||||
|
||||
this._sources[channel.get_object_path()] = source;
|
||||
this._chatSources[channel.get_object_path()] = source;
|
||||
source.connect('destroy', Lang.bind(this,
|
||||
function() {
|
||||
if (this._tpClient.is_handling_channel(channel)) {
|
||||
@ -154,10 +163,16 @@ Client.prototype = {
|
||||
});
|
||||
}
|
||||
|
||||
delete this._sources[channel.get_object_path()];
|
||||
delete this._chatSources[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++) {
|
||||
@ -171,40 +186,127 @@ Client.prototype = {
|
||||
|
||||
if (this._tpClient.is_handling_channel(channel)) {
|
||||
// We are already handling the channel, display the source
|
||||
let source = this._sources[channel.get_object_path()];
|
||||
let source = this._chatSources[channel.get_object_path()];
|
||||
if (source)
|
||||
source.notify();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_approveChannels: function(approver, account, conn, channels,
|
||||
dispatchOp, context) {
|
||||
// Approve the 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, channels);
|
||||
} catch (err) {
|
||||
global.logError('Failed to Claim channel: ' + err);
|
||||
}}));
|
||||
_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();
|
||||
},
|
||||
|
||||
_handleChannels: function(handler, account, conn, channels,
|
||||
requests, user_action_time, context) {
|
||||
this._handlingChannels(account, conn, channels);
|
||||
_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 Source(account, conn, channel, contact, client) {
|
||||
function ChatSource(account, conn, channel, contact, client) {
|
||||
this._init(account, conn, channel, contact, client);
|
||||
}
|
||||
|
||||
Source.prototype = {
|
||||
ChatSource.prototype = {
|
||||
__proto__: MessageTray.Source.prototype,
|
||||
|
||||
_init: function(account, conn, channel, contact, client) {
|
||||
@ -222,7 +324,7 @@ Source.prototype = {
|
||||
this._channel = channel;
|
||||
this._closedId = this._channel.connect('invalidated', Lang.bind(this, this._channelClosed));
|
||||
|
||||
this._notification = new Notification(this);
|
||||
this._notification = new ChatNotification(this);
|
||||
this._notification.setUrgency(MessageTray.Urgency.HIGH);
|
||||
|
||||
// We ack messages when the message box is collapsed if user has
|
||||
@ -326,6 +428,8 @@ Source.prototype = {
|
||||
this._pendingMessages.push(message);
|
||||
}
|
||||
|
||||
this._updateCount();
|
||||
|
||||
let showTimestamp = false;
|
||||
|
||||
for (let i = 0; i < logMessages.length; i++) {
|
||||
@ -370,11 +474,16 @@ Source.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);
|
||||
@ -407,6 +516,19 @@ Source.prototype = {
|
||||
}));
|
||||
},
|
||||
|
||||
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) {
|
||||
let msg, shouldNotify, title;
|
||||
|
||||
@ -445,8 +567,10 @@ Source.prototype = {
|
||||
_pendingRemoved: function(channel, message) {
|
||||
let idx = this._pendingMessages.indexOf(message);
|
||||
|
||||
if (idx >= 0)
|
||||
if (idx >= 0) {
|
||||
this._pendingMessages.splice(idx, 1);
|
||||
this._updateCount();
|
||||
}
|
||||
else
|
||||
throw new Error('Message not in our pending list: ' + message);
|
||||
},
|
||||
@ -480,11 +604,11 @@ Source.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
function Notification(source) {
|
||||
function ChatNotification(source) {
|
||||
this._init(source);
|
||||
}
|
||||
|
||||
Notification.prototype = {
|
||||
ChatNotification.prototype = {
|
||||
__proto__: MessageTray.Notification.prototype,
|
||||
|
||||
_init: function(source) {
|
||||
@ -494,6 +618,7 @@ Notification.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;
|
||||
@ -510,6 +635,7 @@ Notification.prototype = {
|
||||
|
||||
this._history = [];
|
||||
this._timestampTimeoutId = 0;
|
||||
this._composingTimeoutId = 0;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -682,5 +808,166 @@ Notification.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();
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
@ -141,13 +141,19 @@ SearchTab.prototype = {
|
||||
'edit-find');
|
||||
|
||||
this._text.connect('text-changed', Lang.bind(this, this._onTextChanged));
|
||||
this._text.connect('activate', Lang.bind(this, function (se) {
|
||||
if (this._searchTimeoutId > 0) {
|
||||
Mainloop.source_remove(this._searchTimeoutId);
|
||||
this._doSearch();
|
||||
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._searchResults.activateSelected();
|
||||
return true;
|
||||
return false;
|
||||
}));
|
||||
|
||||
this._entry.connect('notify::mapped', Lang.bind(this, this._onMapped));
|
||||
|
@ -119,6 +119,8 @@ 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() {
|
||||
@ -180,7 +182,7 @@ WindowManager.prototype = {
|
||||
*/
|
||||
this._minimizing.push(actor);
|
||||
|
||||
let primary = global.get_primary_monitor();
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
let xDest = primary.x;
|
||||
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
|
||||
xDest += primary.width;
|
||||
@ -534,7 +536,7 @@ WindowManager.prototype = {
|
||||
|
||||
let tabPopup = new AltTab.AltTabPopup();
|
||||
|
||||
if (!tabPopup.show(backwards, binding == 'switch_group'))
|
||||
if (!tabPopup.show(backwards, binding))
|
||||
tabPopup.destroy();
|
||||
},
|
||||
|
||||
|
@ -225,8 +225,12 @@ WindowClone.prototype = {
|
||||
let [width, height] = this.actor.get_transformed_size();
|
||||
|
||||
let monitorIndex = this.metaWindow.get_monitor();
|
||||
let availArea = global.get_monitors()[monitorIndex];
|
||||
if (monitorIndex == global.get_primary_monitor_index()) {
|
||||
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) {
|
||||
availArea.y += Main.panel.actor.height;
|
||||
availArea.height -= Main.panel.actor.height;
|
||||
}
|
||||
@ -593,7 +597,7 @@ Workspace.prototype = {
|
||||
this._height = 0;
|
||||
|
||||
this.monitorIndex = monitorIndex;
|
||||
this._monitor = global.get_monitors()[this.monitorIndex];
|
||||
this._monitor = Main.layoutManager.monitors[this.monitorIndex];
|
||||
this._windowOverlaysGroup = new Clutter.Group();
|
||||
// Without this the drop area will be overlapped.
|
||||
this._windowOverlaysGroup.set_size(0, 0);
|
||||
|
@ -56,7 +56,7 @@ WorkspaceSwitcherPopup.prototype = {
|
||||
|
||||
_getPreferredHeight : function (actor, forWidth, alloc) {
|
||||
let children = this._list.get_children();
|
||||
let primary = global.get_primary_monitor();
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
|
||||
let availHeight = primary.height;
|
||||
availHeight -= Main.panel.actor.height;
|
||||
@ -82,7 +82,7 @@ WorkspaceSwitcherPopup.prototype = {
|
||||
},
|
||||
|
||||
_getPreferredWidth : function (actor, forHeight, alloc) {
|
||||
let primary = global.get_primary_monitor();
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
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 = global.get_primary_monitor();
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
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);
|
||||
|
@ -146,7 +146,7 @@ function WorkspaceThumbnail(metaWorkspace) {
|
||||
WorkspaceThumbnail.prototype = {
|
||||
_init : function(metaWorkspace) {
|
||||
this.metaWorkspace = metaWorkspace;
|
||||
this.monitorIndex = global.get_primary_monitor_index();
|
||||
this.monitorIndex = Main.layoutManager.primaryIndex;
|
||||
|
||||
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 = global.get_primary_monitor();
|
||||
let monitor = Main.layoutManager.primaryMonitor;
|
||||
this.setPorthole(monitor.x, monitor.y, monitor.width, monitor.height);
|
||||
|
||||
let windows = global.get_window_actors().filter(this._isMyWindow, this);
|
||||
@ -528,7 +528,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 = global.get_primary_monitor();
|
||||
let monitor = Main.layoutManager.primaryMonitor;
|
||||
this._porthole = {
|
||||
x: monitor.x,
|
||||
y: monitor.y + panelHeight,
|
||||
|
@ -70,10 +70,10 @@ WorkspacesView.prototype = {
|
||||
this._workspaces[activeWorkspaceIndex].actor.raise_top();
|
||||
|
||||
this._extraWorkspaces = [];
|
||||
let monitors = global.get_monitors();
|
||||
let monitors = Main.layoutManager.monitors;
|
||||
let m = 0;
|
||||
for (let i = 0; i < monitors.length; i++) {
|
||||
if (i == global.get_primary_monitor_index())
|
||||
if (i == Main.layoutManager.primaryIndex)
|
||||
continue;
|
||||
let ws = new Workspace.Workspace(null, i);
|
||||
this._extraWorkspaces[m++] = ws;
|
||||
@ -383,7 +383,7 @@ WorkspacesView.prototype = {
|
||||
this._extraWorkspaces[i].setReservedSlot(dragEvent.dragActor._delegate);
|
||||
}
|
||||
|
||||
let primary = global.get_primary_monitor();
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
|
||||
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
|
||||
let topWorkspace, bottomWorkspace;
|
||||
@ -550,8 +550,8 @@ WorkspacesDisplay.prototype = {
|
||||
controls.connect('scroll-event',
|
||||
Lang.bind(this, this._onScrollEvent));
|
||||
|
||||
this._monitorIndex = global.get_primary_monitor_index();
|
||||
this._monitor = global.get_monitors()[this._monitorIndex];
|
||||
this._monitorIndex = Main.layoutManager.primaryIndex;
|
||||
this._monitor = Main.layoutManager.monitors[this._monitorIndex];
|
||||
|
||||
this._thumbnailsBox = new WorkspaceThumbnail.ThumbnailsBox();
|
||||
controls.add_actor(this._thumbnailsBox.actor);
|
||||
@ -567,7 +567,7 @@ WorkspacesDisplay.prototype = {
|
||||
|
||||
this._updateAlwaysZoom();
|
||||
|
||||
global.screen.connect('monitors-changed', Lang.bind(this, this._updateAlwaysZoom));
|
||||
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._updateAlwaysZoom));
|
||||
global.screen.connect('notify::n-workspaces',
|
||||
Lang.bind(this, this._workspacesChanged));
|
||||
|
||||
@ -694,8 +694,8 @@ WorkspacesDisplay.prototype = {
|
||||
if (this._alwaysZoomOut)
|
||||
return;
|
||||
|
||||
let monitors = global.get_monitors();
|
||||
let primary = global.get_primary_monitor();
|
||||
let monitors = Main.layoutManager.monitors;
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
|
||||
/* Look for any monitor to the right of the primary, if there is
|
||||
* one, we always keep zoom out, otherwise its hard to reach
|
||||
|
261
po/es.po
261
po/es.po
@ -2,22 +2,22 @@
|
||||
# Copyright (C) 2009 gnome-shell's COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the gnome-shell package.
|
||||
# Benjamín Valero Espinosa <benjavalero@gmail.com>, 2011.
|
||||
# Jorge González <jorgegonz@svn.gnome.org>, 2009, 2010, 2011.
|
||||
# Daniel Mustieles <daniel.mustieles@gmail.com>, 2010, 2011.
|
||||
# Jorge González <jorgegonz@svn.gnome.org>, 2009, 2010, 2011.
|
||||
#
|
||||
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"
|
||||
"POT-Creation-Date: 2011-06-27 15:22+0000\n"
|
||||
"PO-Revision-Date: 2011-06-28 11:17+0200\n"
|
||||
"Last-Translator: Daniel Mustieles <daniel.mustieles@gmail.com>\n"
|
||||
"Language-Team: Español <gnome-es-list@gnome.org>\n"
|
||||
"POT-Creation-Date: 2011-07-15 16:19+0000\n"
|
||||
"PO-Revision-Date: 2011-07-17 11:59+0200\n"
|
||||
"Last-Translator: Jorge González <jorgegonz@svn.gnome.org>\n"
|
||||
"Language-Team: Español; Castellano <gnome-es-list@gnome.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"Content-Transfer-Encoding: 8bits\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n!=1);\n"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:1
|
||||
msgid "GNOME Shell"
|
||||
@ -108,16 +108,16 @@ msgid ""
|
||||
"at the optimal thread count on the system."
|
||||
msgstr ""
|
||||
"Establece la tubería GStreamer usada para codificar grabaciones. Sigue la "
|
||||
"sintaxis usada para gst-launch. La tubería debería tener un sumidero («sink») "
|
||||
"de ensamblaje/sesensamblaje donde el vídeo que se está grabando se graba. "
|
||||
"Generalmente tendrá un origen de ensamblado/desensamblado; la salida de ese "
|
||||
"punto se escibirá en el archivo de salida. No obstante la tubería también "
|
||||
"puede tomar parte en su propia salida; esto se puede usar para enviar la "
|
||||
"salida a un servidor «icecast» a través de shout2send o similar. Cuando no "
|
||||
"está establecido o lo está a un valor vacío, se usará la tubería "
|
||||
"predeterminada. Actualmente es «videorate ! vp8enc quality=10 speed=2 threads="
|
||||
"%T ! queue ! webmmux» y greba en WEBM usando el códec VP8. Se usa %T como "
|
||||
"suposición para el número de hilos óptimos en el sistema."
|
||||
"sintaxis usada para gst-launch. La tubería debería tener un sumidero "
|
||||
"(«sink») de ensamblaje/sesensamblaje donde el vídeo que se está grabando se "
|
||||
"graba. Generalmente tendrá un origen de ensamblado/desensamblado; la salida "
|
||||
"de ese punto se escibirá en el archivo de salida. No obstante la tubería "
|
||||
"también puede tomar parte en su propia salida; esto se puede usar para "
|
||||
"enviar la salida a un servidor «icecast» a través de shout2send o similar. "
|
||||
"Cuando no está establecido o lo está a un valor vacío, se usará la tubería "
|
||||
"predeterminada. Actualmente es «videorate ! vp8enc quality=10 speed=2 "
|
||||
"threads=%T ! queue ! webmmux» y greba en WEBM usando el códec VP8. Se usa %T "
|
||||
"como suposición para el número de hilos óptimos en el sistema."
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:15
|
||||
msgid "Show date in clock"
|
||||
@ -206,27 +206,27 @@ msgid "Execution of '%s' failed:"
|
||||
msgstr "Falló la ejecución de «%s»:"
|
||||
|
||||
#. Translators: Filter to display all applications
|
||||
#: ../js/ui/appDisplay.js:258
|
||||
#: ../js/ui/appDisplay.js:252
|
||||
msgid "All"
|
||||
msgstr "Todas"
|
||||
|
||||
#: ../js/ui/appDisplay.js:357
|
||||
#: ../js/ui/appDisplay.js:351
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "APLICACIONES"
|
||||
|
||||
#: ../js/ui/appDisplay.js:383
|
||||
#: ../js/ui/appDisplay.js:377
|
||||
msgid "SETTINGS"
|
||||
msgstr "CONFIGURACIÓN"
|
||||
|
||||
#: ../js/ui/appDisplay.js:656
|
||||
#: ../js/ui/appDisplay.js:650
|
||||
msgid "New Window"
|
||||
msgstr "Ventana nueva"
|
||||
|
||||
#: ../js/ui/appDisplay.js:659
|
||||
#: ../js/ui/appDisplay.js:653
|
||||
msgid "Remove from Favorites"
|
||||
msgstr "Quitar de los favoritos"
|
||||
|
||||
#: ../js/ui/appDisplay.js:660
|
||||
#: ../js/ui/appDisplay.js:654
|
||||
msgid "Add to Favorites"
|
||||
msgstr "Añadir a los favoritos"
|
||||
|
||||
@ -359,13 +359,13 @@ msgid "Nothing Scheduled"
|
||||
msgstr "Nada programado"
|
||||
|
||||
#. Translators: Shown on calendar heading when selected day occurs on current year
|
||||
#: ../js/ui/calendar.js:717 ../js/ui/telepathyClient.js:564
|
||||
#: ../js/ui/calendar.js:717 ../js/ui/telepathyClient.js:749
|
||||
msgctxt "calendar heading"
|
||||
msgid "%A, %B %d"
|
||||
msgstr "%A, %d de %B"
|
||||
|
||||
#. Translators: Shown on calendar heading when selected day occurs on different year
|
||||
#: ../js/ui/calendar.js:720 ../js/ui/telepathyClient.js:567
|
||||
#: ../js/ui/calendar.js:720 ../js/ui/telepathyClient.js:752
|
||||
msgctxt "calendar heading"
|
||||
msgid "%A, %B %d, %Y"
|
||||
msgstr "%A, %d de %B de %Y"
|
||||
@ -386,7 +386,7 @@ msgstr "Esta semana"
|
||||
msgid "Next week"
|
||||
msgstr "La semana que viene"
|
||||
|
||||
#: ../js/ui/dash.js:172 ../js/ui/messageTray.js:1044
|
||||
#: ../js/ui/dash.js:172 ../js/ui/messageTray.js:1122
|
||||
msgid "Remove"
|
||||
msgstr "Quitar"
|
||||
|
||||
@ -549,11 +549,11 @@ msgstr "Ver fuente"
|
||||
msgid "Web Page"
|
||||
msgstr "Página web"
|
||||
|
||||
#: ../js/ui/messageTray.js:1037
|
||||
#: ../js/ui/messageTray.js:1115
|
||||
msgid "Open"
|
||||
msgstr "Abrir"
|
||||
|
||||
#: ../js/ui/messageTray.js:2208
|
||||
#: ../js/ui/messageTray.js:2286
|
||||
msgid "System Information"
|
||||
msgstr "Información del sistema"
|
||||
|
||||
@ -576,18 +576,18 @@ msgid "Dash"
|
||||
msgstr "Tablero"
|
||||
|
||||
#. TODO - _quit() doesn't really work on apps in state STARTING yet
|
||||
#: ../js/ui/panel.js:533
|
||||
#: ../js/ui/panel.js:532
|
||||
#, c-format
|
||||
msgid "Quit %s"
|
||||
msgstr "Salir de %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
|
||||
#. Translators: If there is no suitable word for "Activities"
|
||||
#. in your language, you can use the word for "Overview".
|
||||
#: ../js/ui/panel.js:568
|
||||
msgid "Activities"
|
||||
msgstr "Actividades"
|
||||
|
||||
#: ../js/ui/panel.js:1015
|
||||
#: ../js/ui/panel.js:951
|
||||
msgid "Top Bar"
|
||||
msgstr "Barra superior"
|
||||
|
||||
@ -653,40 +653,41 @@ msgstr "Buscando…"
|
||||
msgid "No matching results."
|
||||
msgstr "No se encontró ningún resultado coincidente."
|
||||
|
||||
#: ../js/ui/statusMenu.js:160 ../js/ui/statusMenu.js:162
|
||||
#: ../js/ui/statusMenu.js:227
|
||||
#: ../js/ui/statusMenu.js:192 ../js/ui/statusMenu.js:196
|
||||
#: ../js/ui/statusMenu.js:262
|
||||
msgid "Power Off..."
|
||||
msgstr "Apagar…"
|
||||
|
||||
#: ../js/ui/statusMenu.js:162 ../js/ui/statusMenu.js:226
|
||||
#: ../js/ui/statusMenu.js:194 ../js/ui/statusMenu.js:196
|
||||
#: ../js/ui/statusMenu.js:261
|
||||
msgid "Suspend"
|
||||
msgstr "Suspender"
|
||||
|
||||
#: ../js/ui/statusMenu.js:183
|
||||
#: ../js/ui/statusMenu.js:217
|
||||
msgid "Available"
|
||||
msgstr "Disponible"
|
||||
|
||||
#: ../js/ui/statusMenu.js:188
|
||||
#: ../js/ui/statusMenu.js:222
|
||||
msgid "Busy"
|
||||
msgstr "Ocupado"
|
||||
|
||||
#: ../js/ui/statusMenu.js:196
|
||||
#: ../js/ui/statusMenu.js:230
|
||||
msgid "My Account"
|
||||
msgstr "Mi cuenta"
|
||||
|
||||
#: ../js/ui/statusMenu.js:200
|
||||
#: ../js/ui/statusMenu.js:234
|
||||
msgid "System Settings"
|
||||
msgstr "Configuración del sistema"
|
||||
|
||||
#: ../js/ui/statusMenu.js:207
|
||||
#: ../js/ui/statusMenu.js:242
|
||||
msgid "Lock Screen"
|
||||
msgstr "Bloquear la pantalla"
|
||||
|
||||
#: ../js/ui/statusMenu.js:212
|
||||
#: ../js/ui/statusMenu.js:247
|
||||
msgid "Switch User"
|
||||
msgstr "Cambiar de usuario"
|
||||
|
||||
#: ../js/ui/statusMenu.js:217
|
||||
#: ../js/ui/statusMenu.js:252
|
||||
msgid "Log Out..."
|
||||
msgstr "Cerrar la sesión…"
|
||||
|
||||
@ -756,7 +757,6 @@ msgstr "Configuración de Bluetooth"
|
||||
|
||||
#. TRANSLATORS: this means that bluetooth was disabled by hardware rfkill
|
||||
#: ../js/ui/status/bluetooth.js:116
|
||||
#| msgid "disabled"
|
||||
msgid "hardware disabled"
|
||||
msgstr "hardware desactivado"
|
||||
|
||||
@ -819,7 +819,7 @@ msgstr "Conceder acceso siempre"
|
||||
msgid "Grant this time only"
|
||||
msgstr "Conceder sólo esta vez"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:409
|
||||
#: ../js/ui/status/bluetooth.js:409 ../js/ui/telepathyClient.js:954
|
||||
msgid "Reject"
|
||||
msgstr "Rechazar"
|
||||
|
||||
@ -908,13 +908,13 @@ msgstr "no disponible"
|
||||
msgid "connection failed"
|
||||
msgstr "falló la conexión"
|
||||
|
||||
#: ../js/ui/status/network.js:582 ../js/ui/status/network.js:1489
|
||||
#: ../js/ui/status/network.js:582 ../js/ui/status/network.js:1507
|
||||
msgid "More..."
|
||||
msgstr "Más…"
|
||||
|
||||
#. 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:618 ../js/ui/status/network.js:1427
|
||||
#: ../js/ui/status/network.js:618 ../js/ui/status/network.js:1444
|
||||
msgid "Connected (private)"
|
||||
msgstr "Conectada (privada)"
|
||||
|
||||
@ -931,7 +931,7 @@ msgid "Auto dial-up"
|
||||
msgstr "Marcado automático"
|
||||
|
||||
#. TRANSLATORS: this the automatic wireless connection name (including the network name)
|
||||
#: ../js/ui/status/network.js:898 ../js/ui/status/network.js:1439
|
||||
#: ../js/ui/status/network.js:898 ../js/ui/status/network.js:1456
|
||||
#, c-format
|
||||
msgid "Auto %s"
|
||||
msgstr "%s automática"
|
||||
@ -940,68 +940,68 @@ msgstr "%s automática"
|
||||
msgid "Auto bluetooth"
|
||||
msgstr "Bluetooth automático"
|
||||
|
||||
#: ../js/ui/status/network.js:1441
|
||||
#: ../js/ui/status/network.js:1458
|
||||
msgid "Auto wireless"
|
||||
msgstr "Inalámbrica automática"
|
||||
|
||||
#: ../js/ui/status/network.js:1531
|
||||
#: ../js/ui/status/network.js:1550
|
||||
msgid "Enable networking"
|
||||
msgstr "Activar red"
|
||||
|
||||
#: ../js/ui/status/network.js:1543
|
||||
#: ../js/ui/status/network.js:1562
|
||||
msgid "Wired"
|
||||
msgstr "Cableada"
|
||||
|
||||
#: ../js/ui/status/network.js:1554
|
||||
#: ../js/ui/status/network.js:1573
|
||||
msgid "Wireless"
|
||||
msgstr "Inalámbrica"
|
||||
|
||||
#: ../js/ui/status/network.js:1564
|
||||
#: ../js/ui/status/network.js:1583
|
||||
msgid "Mobile broadband"
|
||||
msgstr "Banda ancha móvil"
|
||||
|
||||
#: ../js/ui/status/network.js:1574
|
||||
#: ../js/ui/status/network.js:1593
|
||||
msgid "VPN Connections"
|
||||
msgstr "Conexiones VPN"
|
||||
|
||||
#: ../js/ui/status/network.js:1586
|
||||
#: ../js/ui/status/network.js:1605
|
||||
msgid "Network Settings"
|
||||
msgstr "Configuración de la red"
|
||||
|
||||
#: ../js/ui/status/network.js:1878
|
||||
#: ../js/ui/status/network.js:1897
|
||||
#, c-format
|
||||
msgid "You're now connected to mobile broadband connection '%s'"
|
||||
msgstr "Ahora está conectado a la red de banda ancha móvil «%s»"
|
||||
|
||||
#: ../js/ui/status/network.js:1882
|
||||
#: ../js/ui/status/network.js:1901
|
||||
#, c-format
|
||||
msgid "You're now connected to wireless network '%s'"
|
||||
msgstr "Ahora está conectado a la red inalámbrica «%s»"
|
||||
|
||||
#: ../js/ui/status/network.js:1886
|
||||
#: ../js/ui/status/network.js:1905
|
||||
#, c-format
|
||||
msgid "You're now connected to wired network '%s'"
|
||||
msgstr "Ahora está conectado a la red cableada «%s»"
|
||||
|
||||
#: ../js/ui/status/network.js:1890
|
||||
#: ../js/ui/status/network.js:1909
|
||||
#, c-format
|
||||
msgid "You're now connected to VPN network '%s'"
|
||||
msgstr "Ahora está conectado a la VPN «%s»"
|
||||
|
||||
#: ../js/ui/status/network.js:1895
|
||||
#: ../js/ui/status/network.js:1914
|
||||
#, c-format
|
||||
msgid "You're now connected to '%s'"
|
||||
msgstr "Ahora está conectado a «%s»"
|
||||
|
||||
#: ../js/ui/status/network.js:1903
|
||||
#: ../js/ui/status/network.js:1922
|
||||
msgid "Connection established"
|
||||
msgstr "Conexión establecida"
|
||||
|
||||
#: ../js/ui/status/network.js:2029
|
||||
#: ../js/ui/status/network.js:2048
|
||||
msgid "Networking is disabled"
|
||||
msgstr "La red está desactivada"
|
||||
|
||||
#: ../js/ui/status/network.js:2154
|
||||
#: ../js/ui/status/network.js:2173
|
||||
msgid "Network Manager"
|
||||
msgstr "Gestor de la red"
|
||||
|
||||
@ -1011,11 +1011,11 @@ msgstr "Configuración de energía"
|
||||
|
||||
#. 0 is reported when UPower does not have enough data
|
||||
#. to estimate battery life
|
||||
#: ../js/ui/status/power.js:110
|
||||
#: ../js/ui/status/power.js:109
|
||||
msgid "Estimating..."
|
||||
msgstr "Estimando…"
|
||||
|
||||
#: ../js/ui/status/power.js:117
|
||||
#: ../js/ui/status/power.js:116
|
||||
#, c-format
|
||||
msgid "%d hour remaining"
|
||||
msgid_plural "%d hours remaining"
|
||||
@ -1023,75 +1023,75 @@ msgstr[0] "Queda %d hora"
|
||||
msgstr[1] "Queda %d horas"
|
||||
|
||||
#. TRANSLATORS: this is a time string, as in "%d hours %d minutes remaining"
|
||||
#: ../js/ui/status/power.js:120
|
||||
#: ../js/ui/status/power.js:119
|
||||
#, c-format
|
||||
msgid "%d %s %d %s remaining"
|
||||
msgstr "Quedan %d %s %d %s"
|
||||
|
||||
#: ../js/ui/status/power.js:122
|
||||
#: ../js/ui/status/power.js:121
|
||||
msgid "hour"
|
||||
msgid_plural "hours"
|
||||
msgstr[0] "hora"
|
||||
msgstr[1] "horas"
|
||||
|
||||
#: ../js/ui/status/power.js:122
|
||||
#: ../js/ui/status/power.js:121
|
||||
msgid "minute"
|
||||
msgid_plural "minutes"
|
||||
msgstr[0] "minuto"
|
||||
msgstr[1] "minutos"
|
||||
|
||||
#: ../js/ui/status/power.js:125
|
||||
#: ../js/ui/status/power.js:124
|
||||
#, c-format
|
||||
msgid "%d minute remaining"
|
||||
msgid_plural "%d minutes remaining"
|
||||
msgstr[0] "Queda %d minuto"
|
||||
msgstr[1] "Quedan %d minutos"
|
||||
|
||||
#: ../js/ui/status/power.js:227
|
||||
#: ../js/ui/status/power.js:216
|
||||
msgid "AC adapter"
|
||||
msgstr "Adaptador de corriente"
|
||||
|
||||
#: ../js/ui/status/power.js:229
|
||||
#: ../js/ui/status/power.js:218
|
||||
msgid "Laptop battery"
|
||||
msgstr "Batería del portátil"
|
||||
|
||||
#: ../js/ui/status/power.js:231
|
||||
#: ../js/ui/status/power.js:220
|
||||
msgid "UPS"
|
||||
msgstr "SAI"
|
||||
|
||||
#: ../js/ui/status/power.js:233
|
||||
#: ../js/ui/status/power.js:222
|
||||
msgid "Monitor"
|
||||
msgstr "Monitor"
|
||||
|
||||
#: ../js/ui/status/power.js:235
|
||||
#: ../js/ui/status/power.js:224
|
||||
msgid "Mouse"
|
||||
msgstr "Ratón"
|
||||
|
||||
#: ../js/ui/status/power.js:237
|
||||
#: ../js/ui/status/power.js:226
|
||||
msgid "Keyboard"
|
||||
msgstr "Teclado"
|
||||
|
||||
#: ../js/ui/status/power.js:239
|
||||
#: ../js/ui/status/power.js:228
|
||||
msgid "PDA"
|
||||
msgstr "PDA"
|
||||
|
||||
#: ../js/ui/status/power.js:241
|
||||
#: ../js/ui/status/power.js:230
|
||||
msgid "Cell phone"
|
||||
msgstr "Teléfono móvil"
|
||||
|
||||
#: ../js/ui/status/power.js:243
|
||||
#: ../js/ui/status/power.js:232
|
||||
msgid "Media player"
|
||||
msgstr "Reproductor multimedia"
|
||||
|
||||
#: ../js/ui/status/power.js:245
|
||||
#: ../js/ui/status/power.js:234
|
||||
msgid "Tablet"
|
||||
msgstr "Tableta"
|
||||
|
||||
#: ../js/ui/status/power.js:247
|
||||
#: ../js/ui/status/power.js:236
|
||||
msgid "Computer"
|
||||
msgstr "Equipo"
|
||||
|
||||
#: ../js/ui/status/power.js:249 ../src/shell-app-system.c:1088
|
||||
#: ../js/ui/status/power.js:238 ../src/shell-app-system.c:1088
|
||||
msgid "Unknown"
|
||||
msgstr "Desconocido"
|
||||
|
||||
@ -1103,22 +1103,35 @@ msgstr "Volumen"
|
||||
msgid "Microphone"
|
||||
msgstr "Micrófono"
|
||||
|
||||
#: ../js/ui/telepathyClient.js:397
|
||||
#. We got the TpContact
|
||||
#. FIXME: We don't have a 'chat room' icon (bgo #653737) use
|
||||
#. system-users for now as Empathy does.
|
||||
#: ../js/ui/telepathyClient.js:222
|
||||
msgid "Invitation"
|
||||
msgstr "Invitación"
|
||||
|
||||
#. We got the TpContact
|
||||
#: ../js/ui/telepathyClient.js:285
|
||||
#| msgid "Cancel"
|
||||
msgid "Call"
|
||||
msgstr "Llamar"
|
||||
|
||||
#: ../js/ui/telepathyClient.js:541
|
||||
#, c-format
|
||||
msgid "%s is online."
|
||||
msgstr "%s está conectado/a."
|
||||
|
||||
#: ../js/ui/telepathyClient.js:402
|
||||
#: ../js/ui/telepathyClient.js:546
|
||||
#, c-format
|
||||
msgid "%s is offline."
|
||||
msgstr "%s está desconectado/a."
|
||||
|
||||
#: ../js/ui/telepathyClient.js:405
|
||||
#: ../js/ui/telepathyClient.js:549
|
||||
#, c-format
|
||||
msgid "%s is away."
|
||||
msgstr "%s está ausente."
|
||||
|
||||
#: ../js/ui/telepathyClient.js:408
|
||||
#: ../js/ui/telepathyClient.js:552
|
||||
#, c-format
|
||||
msgid "%s is busy."
|
||||
msgstr "%s está ocupado/a."
|
||||
@ -1126,18 +1139,57 @@ msgstr "%s está ocupado/a."
|
||||
#. 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:556
|
||||
#: ../js/ui/telepathyClient.js:741
|
||||
#, no-c-format
|
||||
msgid "Sent at %X on %A"
|
||||
msgstr "Enviado a las %X el %A"
|
||||
|
||||
#. Translators: this is the other person changing their old IM name to their new
|
||||
#. IM name.
|
||||
#: ../js/ui/telepathyClient.js:606
|
||||
#: ../js/ui/telepathyClient.js:791
|
||||
#, c-format
|
||||
msgid "%s is now known as %s"
|
||||
msgstr "Ahora %s se llama %s"
|
||||
|
||||
#. translators: argument is a room name like
|
||||
#. * room@jabber.org for example.
|
||||
#: ../js/ui/telepathyClient.js:898
|
||||
#, c-format
|
||||
msgid "Invitation to %s"
|
||||
msgstr "Invitación a %s"
|
||||
|
||||
#. 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.
|
||||
#: ../js/ui/telepathyClient.js:906
|
||||
#, c-format
|
||||
msgid "%s is inviting you to join %s"
|
||||
msgstr "%s le está invitando a unirse a %s"
|
||||
|
||||
#: ../js/ui/telepathyClient.js:908
|
||||
msgid "Decline"
|
||||
msgstr "Rechazar"
|
||||
|
||||
#: ../js/ui/telepathyClient.js:909
|
||||
msgid "Accept"
|
||||
msgstr "Aceptar"
|
||||
|
||||
#. translators: argument is a contact name like Alice for example.
|
||||
#: ../js/ui/telepathyClient.js:942
|
||||
#, c-format
|
||||
msgid "Video call from %s"
|
||||
msgstr "Videollamada de %s"
|
||||
|
||||
#. translators: argument is a contact name like Alice for example.
|
||||
#: ../js/ui/telepathyClient.js:945
|
||||
#, c-format
|
||||
msgid "Call from %s"
|
||||
msgstr "Llamada de %s"
|
||||
|
||||
#: ../js/ui/telepathyClient.js:955
|
||||
msgid "Answer"
|
||||
msgstr "Responder"
|
||||
|
||||
#. Translators: this is the text displayed
|
||||
#. in the search entry when no search is
|
||||
#. active; it should not exceed ~30
|
||||
@ -1146,7 +1198,7 @@ msgstr "Ahora %s se llama %s"
|
||||
msgid "Type to search..."
|
||||
msgstr "Teclear para buscar…"
|
||||
|
||||
#: ../js/ui/viewSelector.js:140 ../src/shell-util.c:254
|
||||
#: ../js/ui/viewSelector.js:140 ../src/shell-util.c:257
|
||||
msgid "Search"
|
||||
msgstr "Buscar"
|
||||
|
||||
@ -1182,7 +1234,7 @@ msgstr[1] "%u entradas"
|
||||
msgid "System Sounds"
|
||||
msgstr "Sonidos del sistema"
|
||||
|
||||
#: ../src/main.c:445
|
||||
#: ../src/main.c:466
|
||||
msgid "Print version"
|
||||
msgstr "Imprimir versión"
|
||||
|
||||
@ -1203,13 +1255,13 @@ msgstr "Predeterminada"
|
||||
msgid "Authentication dialog was dismissed by the user"
|
||||
msgstr "El usuario rechazó el diálogo de autenticación"
|
||||
|
||||
#: ../src/shell-util.c:93
|
||||
#: ../src/shell-util.c:96
|
||||
msgid "Home Folder"
|
||||
msgstr "Carpeta personal"
|
||||
|
||||
#. Translators: this is the same string as the one found in
|
||||
#. * nautilus
|
||||
#: ../src/shell-util.c:108
|
||||
#: ../src/shell-util.c:111
|
||||
msgid "File System"
|
||||
msgstr "Sistema de archivos"
|
||||
|
||||
@ -1218,7 +1270,7 @@ msgstr "Sistema de archivos"
|
||||
#. * example, "Trash: some-directory". It means that the
|
||||
#. * directory called "some-directory" is in the trash.
|
||||
#.
|
||||
#: ../src/shell-util.c:304
|
||||
#: ../src/shell-util.c:307
|
||||
#, c-format
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s: %2$s"
|
||||
@ -1447,8 +1499,8 @@ msgstr "%1$s: %2$s"
|
||||
#~ "If true and format is either \"12-hour\" or \"24-hour\", display seconds "
|
||||
#~ "in time."
|
||||
#~ msgstr ""
|
||||
#~ "Si es cierta y el formato es «12-horas» o «24-horas», muestra los segundos "
|
||||
#~ "en la hora."
|
||||
#~ "Si es cierta y el formato es «12-horas» o «24-horas», muestra los "
|
||||
#~ "segundos en la hora."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "This key specifies the format used by the panel clock when the format key "
|
||||
@ -1465,18 +1517,19 @@ msgstr "%1$s: %2$s"
|
||||
#~ msgid ""
|
||||
#~ "This key specifies the hour format used by the panel clock. Possible "
|
||||
#~ "values are \"12-hour\", \"24-hour\", \"unix\" and \"custom\". If set to "
|
||||
#~ "\"unix\", the clock will display time in seconds since Epoch, i.e. 1970-"
|
||||
#~ "01-01. If set to \"custom\", the clock will display time according to the "
|
||||
#~ "format specified in the custom_format key. Note that if set to either "
|
||||
#~ "\"unix\" or \"custom\", the show_date and show_seconds keys are ignored."
|
||||
#~ "\"unix\", the clock will display time in seconds since Epoch, i.e. "
|
||||
#~ "1970-01-01. If set to \"custom\", the clock will display time according "
|
||||
#~ "to the format specified in the custom_format key. Note that if set to "
|
||||
#~ "either \"unix\" or \"custom\", the show_date and show_seconds keys are "
|
||||
#~ "ignored."
|
||||
#~ msgstr ""
|
||||
#~ "Esta clave especifica el formato de la hora especificado por el reloj del "
|
||||
#~ "panel. Los valores posibles son «12-hour» (12 horas), «24-hour» (24 horas), "
|
||||
#~ "«unix» y «custom» (personalizado).Si se establece a «unix» el reloj mostrará "
|
||||
#~ "la hora en segundos desde la época (1 de enero de 1970). Si se establece "
|
||||
#~ "a «custom» el reloj mostrará la hora según el formato especificado en la "
|
||||
#~ "clave «custom_format». Note que si se establece a «unix» o «custom» se "
|
||||
#~ "ignoran las claves «show_date» y «show_seconds»."
|
||||
#~ "panel. Los valores posibles son «12-hour» (12 horas), «24-hour» (24 "
|
||||
#~ "horas), «unix» y «custom» (personalizado).Si se establece a «unix» el "
|
||||
#~ "reloj mostrará la hora en segundos desde la época (1 de enero de 1970). "
|
||||
#~ "Si se establece a «custom» el reloj mostrará la hora según el formato "
|
||||
#~ "especificado en la clave «custom_format». Note que si se establece a "
|
||||
#~ "«unix» o «custom» se ignoran las claves «show_date» y «show_seconds»."
|
||||
|
||||
#~ msgid "Clock Format"
|
||||
#~ msgstr "Formato del reloj"
|
||||
|
274
po/gl.po
274
po/gl.po
@ -12,8 +12,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell master\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-06-06 00:46+0200\n"
|
||||
"PO-Revision-Date: 2011-06-06 00:49+0200\n"
|
||||
"POT-Creation-Date: 2011-07-04 22:20+0200\n"
|
||||
"PO-Revision-Date: 2011-07-04 22:20+0200\n"
|
||||
"Last-Translator: Fran Diéguez <frandieguez@gnome.org>\n"
|
||||
"Language-Team: Galician <gnome-l10n-gl@gnome.org>\n"
|
||||
"Language: gl\n"
|
||||
@ -362,13 +362,13 @@ msgid "Nothing Scheduled"
|
||||
msgstr "Nada programado"
|
||||
|
||||
#. Translators: Shown on calendar heading when selected day occurs on current year
|
||||
#: ../js/ui/calendar.js:717 ../js/ui/telepathyClient.js:500
|
||||
#: ../js/ui/calendar.js:717 ../js/ui/telepathyClient.js:623
|
||||
msgctxt "calendar heading"
|
||||
msgid "%A, %B %d"
|
||||
msgstr "%A, %d de %B"
|
||||
|
||||
#. Translators: Shown on calendar heading when selected day occurs on different year
|
||||
#: ../js/ui/calendar.js:720 ../js/ui/telepathyClient.js:503
|
||||
#: ../js/ui/calendar.js:720 ../js/ui/telepathyClient.js:626
|
||||
msgctxt "calendar heading"
|
||||
msgid "%A, %B %d, %Y"
|
||||
msgstr "%A, %d de %B de %Y"
|
||||
@ -389,7 +389,7 @@ msgstr "Esta semana"
|
||||
msgid "Next week"
|
||||
msgstr "A vindeira semana"
|
||||
|
||||
#: ../js/ui/dash.js:172 ../js/ui/messageTray.js:1034
|
||||
#: ../js/ui/dash.js:172 ../js/ui/messageTray.js:1045
|
||||
msgid "Remove"
|
||||
msgstr "Eliminar"
|
||||
|
||||
@ -519,45 +519,45 @@ msgid "Restarting the system."
|
||||
msgstr "Reiniciando o computador."
|
||||
|
||||
#: ../js/ui/endSessionDialog.js:410 ../js/ui/polkitAuthenticationAgent.js:170
|
||||
#: ../js/ui/status/bluetooth.js:488
|
||||
#: ../js/ui/status/bluetooth.js:497
|
||||
msgid "Cancel"
|
||||
msgstr "Cancelar"
|
||||
|
||||
#: ../js/ui/lookingGlass.js:594
|
||||
#: ../js/ui/lookingGlass.js:641
|
||||
msgid "No extensions installed"
|
||||
msgstr "Non hai ningunha extensión instalada"
|
||||
|
||||
#: ../js/ui/lookingGlass.js:631
|
||||
#: ../js/ui/lookingGlass.js:678
|
||||
msgid "Enabled"
|
||||
msgstr "Activado"
|
||||
|
||||
#. translators:
|
||||
#. * The device has been disabled
|
||||
#: ../js/ui/lookingGlass.js:633 ../src/gvc/gvc-mixer-control.c:1091
|
||||
#: ../js/ui/lookingGlass.js:680 ../src/gvc/gvc-mixer-control.c:1091
|
||||
msgid "Disabled"
|
||||
msgstr "Desactivado"
|
||||
|
||||
#: ../js/ui/lookingGlass.js:635
|
||||
#: ../js/ui/lookingGlass.js:682
|
||||
msgid "Error"
|
||||
msgstr "Erro"
|
||||
|
||||
#: ../js/ui/lookingGlass.js:637
|
||||
#: ../js/ui/lookingGlass.js:684
|
||||
msgid "Out of date"
|
||||
msgstr "Desactualizado"
|
||||
|
||||
#: ../js/ui/lookingGlass.js:662
|
||||
#: ../js/ui/lookingGlass.js:709
|
||||
msgid "View Source"
|
||||
msgstr "Ver fonte"
|
||||
|
||||
#: ../js/ui/lookingGlass.js:668
|
||||
#: ../js/ui/lookingGlass.js:715
|
||||
msgid "Web Page"
|
||||
msgstr "Páxina web"
|
||||
|
||||
#: ../js/ui/messageTray.js:1027
|
||||
#: ../js/ui/messageTray.js:1038
|
||||
msgid "Open"
|
||||
msgstr "Abrir"
|
||||
|
||||
#: ../js/ui/messageTray.js:2197
|
||||
#: ../js/ui/messageTray.js:2210
|
||||
msgid "System Information"
|
||||
msgstr "Información do sistema"
|
||||
|
||||
@ -591,7 +591,7 @@ msgstr "Saír de %s"
|
||||
msgid "Activities"
|
||||
msgstr "Actividades"
|
||||
|
||||
#: ../js/ui/panel.js:1015
|
||||
#: ../js/ui/panel.js:1013
|
||||
msgid "Top Bar"
|
||||
msgstr "Barra superior"
|
||||
|
||||
@ -649,52 +649,53 @@ msgstr "toggle-switch-intl"
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Insira unha orde:"
|
||||
|
||||
#: ../js/ui/searchDisplay.js:311
|
||||
#: ../js/ui/searchDisplay.js:318
|
||||
msgid "Searching..."
|
||||
msgstr "Buscando..."
|
||||
|
||||
#: ../js/ui/searchDisplay.js:325
|
||||
#: ../js/ui/searchDisplay.js:332
|
||||
msgid "No matching results."
|
||||
msgstr "Non hai resultados que coincidan."
|
||||
|
||||
#: ../js/ui/statusMenu.js:159 ../js/ui/statusMenu.js:161
|
||||
#: ../js/ui/statusMenu.js:226
|
||||
#: ../js/ui/statusMenu.js:202 ../js/ui/statusMenu.js:206
|
||||
#: ../js/ui/statusMenu.js:272
|
||||
msgid "Power Off..."
|
||||
msgstr "Apagar…"
|
||||
|
||||
#: ../js/ui/statusMenu.js:161 ../js/ui/statusMenu.js:225
|
||||
#: ../js/ui/statusMenu.js:204 ../js/ui/statusMenu.js:206
|
||||
#: ../js/ui/statusMenu.js:271
|
||||
msgid "Suspend"
|
||||
msgstr "Suspender"
|
||||
|
||||
#: ../js/ui/statusMenu.js:182
|
||||
#: ../js/ui/statusMenu.js:227
|
||||
msgid "Available"
|
||||
msgstr "Dispoñíbel"
|
||||
|
||||
#: ../js/ui/statusMenu.js:187
|
||||
#: ../js/ui/statusMenu.js:232
|
||||
msgid "Busy"
|
||||
msgstr "Ocupado"
|
||||
|
||||
#: ../js/ui/statusMenu.js:195
|
||||
#: ../js/ui/statusMenu.js:240
|
||||
msgid "My Account"
|
||||
msgstr "A miña conta"
|
||||
|
||||
#: ../js/ui/statusMenu.js:199
|
||||
#: ../js/ui/statusMenu.js:244
|
||||
msgid "System Settings"
|
||||
msgstr "Configuracións do sistema"
|
||||
|
||||
#: ../js/ui/statusMenu.js:206
|
||||
#: ../js/ui/statusMenu.js:252
|
||||
msgid "Lock Screen"
|
||||
msgstr "Bloquear pantalla"
|
||||
|
||||
#: ../js/ui/statusMenu.js:211
|
||||
#: ../js/ui/statusMenu.js:257
|
||||
msgid "Switch User"
|
||||
msgstr "Cambiar de usuario"
|
||||
|
||||
#: ../js/ui/statusMenu.js:216
|
||||
#: ../js/ui/statusMenu.js:262
|
||||
msgid "Log Out..."
|
||||
msgstr "Saír da sesión…"
|
||||
|
||||
#: ../js/ui/status/accessibility.js:59
|
||||
#: ../js/ui/status/accessibility.js:60
|
||||
msgid "Zoom"
|
||||
msgstr "Ampliación"
|
||||
|
||||
@ -704,41 +705,41 @@ msgstr "Ampliación"
|
||||
#. let screenKeyboard = this._buildItem(_("Screen Keyboard"), APPLICATIONS_SCHEMA,
|
||||
#. 'screen-keyboard-enabled');
|
||||
#. this.menu.addMenuItem(screenKeyboard);
|
||||
#: ../js/ui/status/accessibility.js:74
|
||||
#: ../js/ui/status/accessibility.js:75
|
||||
msgid "Visual Alerts"
|
||||
msgstr "Alertas visuais"
|
||||
|
||||
#: ../js/ui/status/accessibility.js:77
|
||||
#: ../js/ui/status/accessibility.js:78
|
||||
msgid "Sticky Keys"
|
||||
msgstr "Teclas persistentes"
|
||||
|
||||
#: ../js/ui/status/accessibility.js:80
|
||||
#: ../js/ui/status/accessibility.js:81
|
||||
msgid "Slow Keys"
|
||||
msgstr "Teclas lentas"
|
||||
|
||||
#: ../js/ui/status/accessibility.js:83
|
||||
#: ../js/ui/status/accessibility.js:84
|
||||
msgid "Bounce Keys"
|
||||
msgstr "Rebote das teclas"
|
||||
|
||||
#: ../js/ui/status/accessibility.js:86
|
||||
#: ../js/ui/status/accessibility.js:87
|
||||
msgid "Mouse Keys"
|
||||
msgstr "Teclas do Rato"
|
||||
|
||||
#: ../js/ui/status/accessibility.js:90
|
||||
#: ../js/ui/status/accessibility.js:91
|
||||
msgid "Universal Access Settings"
|
||||
msgstr "Configuracións de acceso universal"
|
||||
|
||||
#: ../js/ui/status/accessibility.js:143
|
||||
#: ../js/ui/status/accessibility.js:145
|
||||
msgid "High Contrast"
|
||||
msgstr "Alto contraste"
|
||||
|
||||
#: ../js/ui/status/accessibility.js:180
|
||||
#: ../js/ui/status/accessibility.js:182
|
||||
msgid "Large Text"
|
||||
msgstr "Texto máis grande"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:39 ../js/ui/status/bluetooth.js:261
|
||||
#: ../js/ui/status/bluetooth.js:355 ../js/ui/status/bluetooth.js:389
|
||||
#: ../js/ui/status/bluetooth.js:429 ../js/ui/status/bluetooth.js:462
|
||||
#: ../js/ui/status/bluetooth.js:39 ../js/ui/status/bluetooth.js:270
|
||||
#: ../js/ui/status/bluetooth.js:364 ../js/ui/status/bluetooth.js:398
|
||||
#: ../js/ui/status/bluetooth.js:438 ../js/ui/status/bluetooth.js:471
|
||||
msgid "Bluetooth"
|
||||
msgstr "Bluetooth"
|
||||
|
||||
@ -758,102 +759,115 @@ msgstr "Configurar un dispositivo novo…"
|
||||
msgid "Bluetooth Settings"
|
||||
msgstr "Configuracións de Bluetooth"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:212
|
||||
#. TRANSLATORS: this means that bluetooth was disabled by hardware rfkill
|
||||
#: ../js/ui/status/bluetooth.js:116
|
||||
msgid "hardware disabled"
|
||||
msgstr "hardware desactivado"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:217
|
||||
msgid "Connection"
|
||||
msgstr "Conexión"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:248
|
||||
#: ../js/ui/status/bluetooth.js:226 ../js/ui/status/network.js:493
|
||||
msgid "disconnecting..."
|
||||
msgstr "conectando…"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:239 ../js/ui/status/network.js:499
|
||||
msgid "connecting..."
|
||||
msgstr "conectando…"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:257
|
||||
msgid "Send Files..."
|
||||
msgstr "Enviar ficheiros…"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:253
|
||||
#: ../js/ui/status/bluetooth.js:262
|
||||
msgid "Browse Files..."
|
||||
msgstr "Explorar ficheiros…"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:262
|
||||
#: ../js/ui/status/bluetooth.js:271
|
||||
msgid "Error browsing device"
|
||||
msgstr "Produciuse un erro ao explorar o dispositivo"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:263
|
||||
#: ../js/ui/status/bluetooth.js:272
|
||||
#, c-format
|
||||
msgid "The requested device cannot be browsed, error is '%s'"
|
||||
msgstr "O dispositivo solicitado non pode explorarse, o erro foi «%s»"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:271
|
||||
#: ../js/ui/status/bluetooth.js:280
|
||||
msgid "Keyboard Settings"
|
||||
msgstr "Configuracións do teclado"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:276
|
||||
#: ../js/ui/status/bluetooth.js:285
|
||||
msgid "Mouse Settings"
|
||||
msgstr "Configuracións do rato"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:283 ../js/ui/status/volume.js:63
|
||||
#: ../js/ui/status/bluetooth.js:292 ../js/ui/status/volume.js:64
|
||||
msgid "Sound Settings"
|
||||
msgstr "Configuracións do son"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:390
|
||||
#: ../js/ui/status/bluetooth.js:399
|
||||
#, c-format
|
||||
msgid "Authorization request from %s"
|
||||
msgstr "Solicitude de autorización de %s"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:396
|
||||
#: ../js/ui/status/bluetooth.js:405
|
||||
#, c-format
|
||||
msgid "Device %s wants access to the service '%s'"
|
||||
msgstr "O dispositivo %s quere acceder ao servizo «%s»"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:398
|
||||
#: ../js/ui/status/bluetooth.js:407
|
||||
msgid "Always grant access"
|
||||
msgstr "Conceder acceso sempre"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:399
|
||||
#: ../js/ui/status/bluetooth.js:408
|
||||
msgid "Grant this time only"
|
||||
msgstr "Conceder só esta vez"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:400
|
||||
#: ../js/ui/status/bluetooth.js:409
|
||||
msgid "Reject"
|
||||
msgstr "Rexeitar"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:430
|
||||
#: ../js/ui/status/bluetooth.js:439
|
||||
#, c-format
|
||||
msgid "Pairing confirmation for %s"
|
||||
msgstr "Confirmación de emparellado para «%s»"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:436 ../js/ui/status/bluetooth.js:470
|
||||
#: ../js/ui/status/bluetooth.js:445 ../js/ui/status/bluetooth.js:479
|
||||
#, c-format
|
||||
msgid "Device %s wants to pair with this computer"
|
||||
msgstr "O dispositivo «%s» quere emparellarse con este equipo"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:437
|
||||
#: ../js/ui/status/bluetooth.js:446
|
||||
#, c-format
|
||||
msgid "Please confirm whether the PIN '%s' matches the one on the device."
|
||||
msgstr "Confirme que o PIN mostrado en «%s» coincide co do dispositivo."
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:439
|
||||
#: ../js/ui/status/bluetooth.js:448
|
||||
msgid "Matches"
|
||||
msgstr "Coincide"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:440
|
||||
#: ../js/ui/status/bluetooth.js:449
|
||||
msgid "Does not match"
|
||||
msgstr "Non coincide"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:463
|
||||
#: ../js/ui/status/bluetooth.js:472
|
||||
#, c-format
|
||||
msgid "Pairing request for %s"
|
||||
msgstr "Solicitude de emparellamento para «%s»"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:471
|
||||
#: ../js/ui/status/bluetooth.js:480
|
||||
msgid "Please enter the PIN mentioned on the device."
|
||||
msgstr "Introduza o PIN mencionado no dispositivo."
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:487
|
||||
#: ../js/ui/status/bluetooth.js:496
|
||||
msgid "OK"
|
||||
msgstr "Aceptar"
|
||||
|
||||
#: ../js/ui/status/keyboard.js:70
|
||||
#: ../js/ui/status/keyboard.js:71
|
||||
msgid "Show Keyboard Layout..."
|
||||
msgstr "Mostrar a distribución do teclado…"
|
||||
|
||||
#: ../js/ui/status/keyboard.js:73
|
||||
#: ../js/ui/status/keyboard.js:75
|
||||
msgid "Localization Settings"
|
||||
msgstr "Configuracións do son"
|
||||
|
||||
@ -862,158 +876,150 @@ msgid "<unknown>"
|
||||
msgstr "<descoñecida>"
|
||||
|
||||
#. Translators: this indicates that wireless or wwan is disabled by hardware killswitch
|
||||
#: ../js/ui/status/network.js:340
|
||||
#: ../js/ui/status/network.js:292
|
||||
msgid "disabled"
|
||||
msgstr "desactivada"
|
||||
|
||||
#. 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)
|
||||
#: ../js/ui/status/network.js:535
|
||||
#: ../js/ui/status/network.js:491
|
||||
msgid "unmanaged"
|
||||
msgstr "non xestionada"
|
||||
|
||||
#: ../js/ui/status/network.js:537
|
||||
msgid "disconnecting..."
|
||||
msgstr "conectando…"
|
||||
|
||||
#: ../js/ui/status/network.js:543
|
||||
msgid "connecting..."
|
||||
msgstr "conectando…"
|
||||
|
||||
#. Translators: this is for network connections that require some kind of key or password
|
||||
#: ../js/ui/status/network.js:546
|
||||
#: ../js/ui/status/network.js:502
|
||||
msgid "authentication required"
|
||||
msgstr "autenticación requirida"
|
||||
|
||||
#. Translators: this is for devices that require some kind of firmware or kernel
|
||||
#. module, which is missing
|
||||
#: ../js/ui/status/network.js:556
|
||||
#: ../js/ui/status/network.js:512
|
||||
msgid "firmware missing"
|
||||
msgstr "falta o «firmware»"
|
||||
|
||||
#. Translators: this is for wired network devices that are physically disconnected
|
||||
#: ../js/ui/status/network.js:563
|
||||
#: ../js/ui/status/network.js:519
|
||||
msgid "cable unplugged"
|
||||
msgstr "cable desconectado"
|
||||
|
||||
#. 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:568
|
||||
#: ../js/ui/status/network.js:524
|
||||
msgid "unavailable"
|
||||
msgstr "non dispoñíbel"
|
||||
|
||||
#: ../js/ui/status/network.js:570
|
||||
#: ../js/ui/status/network.js:526
|
||||
msgid "connection failed"
|
||||
msgstr "conexión fallida"
|
||||
|
||||
#: ../js/ui/status/network.js:582 ../js/ui/status/network.js:1489
|
||||
msgid "More..."
|
||||
msgstr "Máis..."
|
||||
|
||||
#. 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:651 ../js/ui/status/network.js:1460
|
||||
#: ../js/ui/status/network.js:618 ../js/ui/status/network.js:1427
|
||||
msgid "Connected (private)"
|
||||
msgstr "Conectado (privado)"
|
||||
|
||||
#: ../js/ui/status/network.js:736
|
||||
#: ../js/ui/status/network.js:703
|
||||
msgid "Auto Ethernet"
|
||||
msgstr "Ethernet automática"
|
||||
|
||||
#: ../js/ui/status/network.js:804
|
||||
#: ../js/ui/status/network.js:771
|
||||
msgid "Auto broadband"
|
||||
msgstr "Banda larga automática"
|
||||
|
||||
#: ../js/ui/status/network.js:807
|
||||
#: ../js/ui/status/network.js:774
|
||||
msgid "Auto dial-up"
|
||||
msgstr "Por liña conmutada automática"
|
||||
|
||||
#. TRANSLATORS: this the automatic wireless connection name (including the network name)
|
||||
#: ../js/ui/status/network.js:931 ../js/ui/status/network.js:1472
|
||||
#: ../js/ui/status/network.js:898 ../js/ui/status/network.js:1439
|
||||
#, c-format
|
||||
msgid "Auto %s"
|
||||
msgstr "%s automática"
|
||||
|
||||
#: ../js/ui/status/network.js:933
|
||||
#: ../js/ui/status/network.js:900
|
||||
msgid "Auto bluetooth"
|
||||
msgstr "Bluetooth automática"
|
||||
|
||||
#: ../js/ui/status/network.js:1474
|
||||
#: ../js/ui/status/network.js:1441
|
||||
msgid "Auto wireless"
|
||||
msgstr "Sen fíos automática"
|
||||
|
||||
#: ../js/ui/status/network.js:1522
|
||||
msgid "More..."
|
||||
msgstr "Máis..."
|
||||
|
||||
#: ../js/ui/status/network.js:1564
|
||||
#: ../js/ui/status/network.js:1531
|
||||
msgid "Enable networking"
|
||||
msgstr "Activar rede"
|
||||
|
||||
#: ../js/ui/status/network.js:1576
|
||||
#: ../js/ui/status/network.js:1543
|
||||
msgid "Wired"
|
||||
msgstr "Con fíos"
|
||||
|
||||
#: ../js/ui/status/network.js:1587
|
||||
#: ../js/ui/status/network.js:1554
|
||||
msgid "Wireless"
|
||||
msgstr "Sen fíos"
|
||||
|
||||
#: ../js/ui/status/network.js:1597
|
||||
#: ../js/ui/status/network.js:1564
|
||||
msgid "Mobile broadband"
|
||||
msgstr "Banda larga móbil"
|
||||
|
||||
#: ../js/ui/status/network.js:1607
|
||||
#: ../js/ui/status/network.js:1574
|
||||
msgid "VPN Connections"
|
||||
msgstr "Conexións VPN"
|
||||
|
||||
#: ../js/ui/status/network.js:1619
|
||||
#: ../js/ui/status/network.js:1586
|
||||
msgid "Network Settings"
|
||||
msgstr "Configuracións da rede"
|
||||
|
||||
#: ../js/ui/status/network.js:1910
|
||||
#: ../js/ui/status/network.js:1878
|
||||
#, c-format
|
||||
msgid "You're now connected to mobile broadband connection '%s'"
|
||||
msgstr "Vostede está conectado agora á conexión de banda larga móbil «%s»"
|
||||
|
||||
#: ../js/ui/status/network.js:1914
|
||||
#: ../js/ui/status/network.js:1882
|
||||
#, c-format
|
||||
msgid "You're now connected to wireless network '%s'"
|
||||
msgstr "Vostede está conectado agora á conexión sen fíos «%s»"
|
||||
|
||||
#: ../js/ui/status/network.js:1918
|
||||
#: ../js/ui/status/network.js:1886
|
||||
#, c-format
|
||||
msgid "You're now connected to wired network '%s'"
|
||||
msgstr "Vostede está conectado agora á conexión con fíos «%s»"
|
||||
|
||||
#: ../js/ui/status/network.js:1922
|
||||
#: ../js/ui/status/network.js:1890
|
||||
#, c-format
|
||||
msgid "You're now connected to VPN network '%s'"
|
||||
msgstr "Vostede está conectado agora á conexión VPN «%s»"
|
||||
|
||||
#: ../js/ui/status/network.js:1927
|
||||
#: ../js/ui/status/network.js:1895
|
||||
#, c-format
|
||||
msgid "You're now connected to '%s'"
|
||||
msgstr "Vostede está conectado agora a «%s»"
|
||||
|
||||
#: ../js/ui/status/network.js:1935
|
||||
#: ../js/ui/status/network.js:1903
|
||||
msgid "Connection established"
|
||||
msgstr "Conexión estabelecida"
|
||||
|
||||
#: ../js/ui/status/network.js:2061
|
||||
#: ../js/ui/status/network.js:2029
|
||||
msgid "Networking is disabled"
|
||||
msgstr "A rede está desactivada"
|
||||
|
||||
#: ../js/ui/status/network.js:2186
|
||||
#: ../js/ui/status/network.js:2154
|
||||
msgid "Network Manager"
|
||||
msgstr "Xestor de rede"
|
||||
|
||||
#: ../js/ui/status/power.js:82
|
||||
#: ../js/ui/status/power.js:83
|
||||
msgid "Power Settings"
|
||||
msgstr "Configuracións de enerxía"
|
||||
|
||||
#. 0 is reported when UPower does not have enough data
|
||||
#. to estimate battery life
|
||||
#: ../js/ui/status/power.js:108
|
||||
#: ../js/ui/status/power.js:110
|
||||
msgid "Estimating..."
|
||||
msgstr "Estimando…"
|
||||
|
||||
#: ../js/ui/status/power.js:115
|
||||
#: ../js/ui/status/power.js:117
|
||||
#, c-format
|
||||
msgid "%d hour remaining"
|
||||
msgid_plural "%d hours remaining"
|
||||
@ -1021,102 +1027,102 @@ msgstr[0] "%d hora restante"
|
||||
msgstr[1] "%d horas restante"
|
||||
|
||||
#. TRANSLATORS: this is a time string, as in "%d hours %d minutes remaining"
|
||||
#: ../js/ui/status/power.js:118
|
||||
#: ../js/ui/status/power.js:120
|
||||
#, c-format
|
||||
msgid "%d %s %d %s remaining"
|
||||
msgstr "%d %s %d %s retante"
|
||||
|
||||
#: ../js/ui/status/power.js:120
|
||||
#: ../js/ui/status/power.js:122
|
||||
msgid "hour"
|
||||
msgid_plural "hours"
|
||||
msgstr[0] "hora"
|
||||
msgstr[1] "horas"
|
||||
|
||||
#: ../js/ui/status/power.js:120
|
||||
#: ../js/ui/status/power.js:122
|
||||
msgid "minute"
|
||||
msgid_plural "minutes"
|
||||
msgstr[0] "minuto"
|
||||
msgstr[1] "minutos"
|
||||
|
||||
#: ../js/ui/status/power.js:123
|
||||
#: ../js/ui/status/power.js:125
|
||||
#, c-format
|
||||
msgid "%d minute remaining"
|
||||
msgid_plural "%d minutes remaining"
|
||||
msgstr[0] "%d minuto restante"
|
||||
msgstr[1] "%d minutos restantes"
|
||||
|
||||
#: ../js/ui/status/power.js:225
|
||||
#: ../js/ui/status/power.js:227
|
||||
msgid "AC adapter"
|
||||
msgstr "Adaptador de corrente"
|
||||
|
||||
#: ../js/ui/status/power.js:227
|
||||
#: ../js/ui/status/power.js:229
|
||||
msgid "Laptop battery"
|
||||
msgstr "Batería do portátil"
|
||||
|
||||
#: ../js/ui/status/power.js:229
|
||||
#: ../js/ui/status/power.js:231
|
||||
msgid "UPS"
|
||||
msgstr "UPS"
|
||||
|
||||
#: ../js/ui/status/power.js:231
|
||||
#: ../js/ui/status/power.js:233
|
||||
msgid "Monitor"
|
||||
msgstr "Monitor"
|
||||
|
||||
#: ../js/ui/status/power.js:233
|
||||
#: ../js/ui/status/power.js:235
|
||||
msgid "Mouse"
|
||||
msgstr "Rato"
|
||||
|
||||
#: ../js/ui/status/power.js:235
|
||||
#: ../js/ui/status/power.js:237
|
||||
msgid "Keyboard"
|
||||
msgstr "Teclado"
|
||||
|
||||
#: ../js/ui/status/power.js:237
|
||||
#: ../js/ui/status/power.js:239
|
||||
msgid "PDA"
|
||||
msgstr "PDA"
|
||||
|
||||
#: ../js/ui/status/power.js:239
|
||||
#: ../js/ui/status/power.js:241
|
||||
msgid "Cell phone"
|
||||
msgstr "Teléfono móbil"
|
||||
|
||||
#: ../js/ui/status/power.js:241
|
||||
#: ../js/ui/status/power.js:243
|
||||
msgid "Media player"
|
||||
msgstr "Reprodutor multimedia"
|
||||
|
||||
#: ../js/ui/status/power.js:243
|
||||
#: ../js/ui/status/power.js:245
|
||||
msgid "Tablet"
|
||||
msgstr "Tablet"
|
||||
|
||||
#: ../js/ui/status/power.js:245
|
||||
#: ../js/ui/status/power.js:247
|
||||
msgid "Computer"
|
||||
msgstr "Computador"
|
||||
|
||||
#: ../js/ui/status/power.js:247 ../src/shell-app-system.c:1088
|
||||
#: ../js/ui/status/power.js:249 ../src/shell-app-system.c:1088
|
||||
msgid "Unknown"
|
||||
msgstr "Descoñecido"
|
||||
|
||||
#: ../js/ui/status/volume.js:42
|
||||
#: ../js/ui/status/volume.js:43
|
||||
msgid "Volume"
|
||||
msgstr "Volume"
|
||||
|
||||
#: ../js/ui/status/volume.js:55
|
||||
#: ../js/ui/status/volume.js:56
|
||||
msgid "Microphone"
|
||||
msgstr "Micrófono"
|
||||
|
||||
#: ../js/ui/telepathyClient.js:339
|
||||
#: ../js/ui/telepathyClient.js:419
|
||||
#, c-format
|
||||
msgid "%s is online."
|
||||
msgstr "%s está conectado/a."
|
||||
|
||||
#: ../js/ui/telepathyClient.js:344
|
||||
#: ../js/ui/telepathyClient.js:424
|
||||
#, c-format
|
||||
msgid "%s is offline."
|
||||
msgstr "%s está desconectado/a."
|
||||
|
||||
#: ../js/ui/telepathyClient.js:347
|
||||
#: ../js/ui/telepathyClient.js:427
|
||||
#, c-format
|
||||
msgid "%s is away."
|
||||
msgstr "%s está ausente."
|
||||
|
||||
#: ../js/ui/telepathyClient.js:350
|
||||
#: ../js/ui/telepathyClient.js:430
|
||||
#, c-format
|
||||
msgid "%s is busy."
|
||||
msgstr "%s está ocupado/a."
|
||||
@ -1124,14 +1130,14 @@ msgstr "%s está ocupado/a."
|
||||
#. 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:492
|
||||
#: ../js/ui/telepathyClient.js:615
|
||||
#, no-c-format
|
||||
msgid "Sent at %X on %A"
|
||||
msgstr "Enviado ás %X o %A"
|
||||
|
||||
#. Translators: this is the other person changing their old IM name to their new
|
||||
#. IM name.
|
||||
#: ../js/ui/telepathyClient.js:537
|
||||
#: ../js/ui/telepathyClient.js:665
|
||||
#, c-format
|
||||
msgid "%s is now known as %s"
|
||||
msgstr "%s é coñecido agora como %s"
|
||||
@ -1144,7 +1150,7 @@ msgstr "%s é coñecido agora como %s"
|
||||
msgid "Type to search..."
|
||||
msgstr "Teclear para buscar…"
|
||||
|
||||
#: ../js/ui/viewSelector.js:140 ../src/shell-util.c:254
|
||||
#: ../js/ui/viewSelector.js:140 ../src/shell-util.c:257
|
||||
msgid "Search"
|
||||
msgstr "Buscar"
|
||||
|
||||
@ -1201,13 +1207,13 @@ msgstr "Predeterminado"
|
||||
msgid "Authentication dialog was dismissed by the user"
|
||||
msgstr "O usuario rexeitou o diálogo de autenticación"
|
||||
|
||||
#: ../src/shell-util.c:93
|
||||
#: ../src/shell-util.c:96
|
||||
msgid "Home Folder"
|
||||
msgstr "Cartafol persoal"
|
||||
|
||||
#. Translators: this is the same string as the one found in
|
||||
#. * nautilus
|
||||
#: ../src/shell-util.c:108
|
||||
#: ../src/shell-util.c:111
|
||||
msgid "File System"
|
||||
msgstr "Sistema de ficheiros"
|
||||
|
||||
@ -1216,7 +1222,7 @@ msgstr "Sistema de ficheiros"
|
||||
#. * example, "Trash: some-directory". It means that the
|
||||
#. * directory called "some-directory" is in the trash.
|
||||
#.
|
||||
#: ../src/shell-util.c:304
|
||||
#: ../src/shell-util.c:307
|
||||
#, c-format
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s: %2$s"
|
||||
|
347
po/he.po
347
po/he.po
@ -8,8 +8,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell master\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-06-04 15:05+0300\n"
|
||||
"PO-Revision-Date: 2011-06-04 15:06+0200\n"
|
||||
"POT-Creation-Date: 2011-07-16 17:26+0300\n"
|
||||
"PO-Revision-Date: 2011-07-16 17:27+0200\n"
|
||||
"Last-Translator: Yaron Shahrabani <sh.yaron@gmail.com>\n"
|
||||
"Language-Team: Hebrew <sh.yaron@gmail.com>\n"
|
||||
"Language: he\n"
|
||||
@ -204,27 +204,27 @@ msgid "Execution of '%s' failed:"
|
||||
msgstr "ההרצה של '%s' נכשלה:"
|
||||
|
||||
#. Translators: Filter to display all applications
|
||||
#: ../js/ui/appDisplay.js:258
|
||||
#: ../js/ui/appDisplay.js:252
|
||||
msgid "All"
|
||||
msgstr "הכול"
|
||||
|
||||
#: ../js/ui/appDisplay.js:357
|
||||
#: ../js/ui/appDisplay.js:351
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "יישומים"
|
||||
|
||||
#: ../js/ui/appDisplay.js:383
|
||||
#: ../js/ui/appDisplay.js:377
|
||||
msgid "SETTINGS"
|
||||
msgstr "הגדרות"
|
||||
|
||||
#: ../js/ui/appDisplay.js:656
|
||||
#: ../js/ui/appDisplay.js:650
|
||||
msgid "New Window"
|
||||
msgstr "חלון חדש"
|
||||
|
||||
#: ../js/ui/appDisplay.js:659
|
||||
#: ../js/ui/appDisplay.js:653
|
||||
msgid "Remove from Favorites"
|
||||
msgstr "הסרה מהמועדפים"
|
||||
|
||||
#: ../js/ui/appDisplay.js:660
|
||||
#: ../js/ui/appDisplay.js:654
|
||||
msgid "Add to Favorites"
|
||||
msgstr "הוספה למועדפים"
|
||||
|
||||
@ -357,13 +357,13 @@ msgid "Nothing Scheduled"
|
||||
msgstr "היומן ריק"
|
||||
|
||||
#. Translators: Shown on calendar heading when selected day occurs on current year
|
||||
#: ../js/ui/calendar.js:717 ../js/ui/telepathyClient.js:500
|
||||
#: ../js/ui/calendar.js:717 ../js/ui/telepathyClient.js:749
|
||||
msgctxt "calendar heading"
|
||||
msgid "%A, %B %d"
|
||||
msgstr "%A, ה־%e ב%B"
|
||||
|
||||
#. Translators: Shown on calendar heading when selected day occurs on different year
|
||||
#: ../js/ui/calendar.js:720 ../js/ui/telepathyClient.js:503
|
||||
#: ../js/ui/calendar.js:720 ../js/ui/telepathyClient.js:752
|
||||
msgctxt "calendar heading"
|
||||
msgid "%A, %B %d, %Y"
|
||||
msgstr "%A, ה־%e ב%B, %Y"
|
||||
@ -384,7 +384,7 @@ msgstr "השבוע"
|
||||
msgid "Next week"
|
||||
msgstr "בשבוע הבא"
|
||||
|
||||
#: ../js/ui/dash.js:172 ../js/ui/messageTray.js:1034
|
||||
#: ../js/ui/dash.js:172 ../js/ui/messageTray.js:1122
|
||||
msgid "Remove"
|
||||
msgstr "הסרה"
|
||||
|
||||
@ -510,45 +510,45 @@ msgid "Restarting the system."
|
||||
msgstr "המערכת מופעלת מחדש"
|
||||
|
||||
#: ../js/ui/endSessionDialog.js:410 ../js/ui/polkitAuthenticationAgent.js:170
|
||||
#: ../js/ui/status/bluetooth.js:488
|
||||
#: ../js/ui/status/bluetooth.js:497
|
||||
msgid "Cancel"
|
||||
msgstr "ביטול"
|
||||
|
||||
#: ../js/ui/lookingGlass.js:594
|
||||
#: ../js/ui/lookingGlass.js:641
|
||||
msgid "No extensions installed"
|
||||
msgstr "לא מותקנות הרחבות"
|
||||
|
||||
#: ../js/ui/lookingGlass.js:631
|
||||
#: ../js/ui/lookingGlass.js:678
|
||||
msgid "Enabled"
|
||||
msgstr "פעיל"
|
||||
|
||||
#. translators:
|
||||
#. * The device has been disabled
|
||||
#: ../js/ui/lookingGlass.js:633 ../src/gvc/gvc-mixer-control.c:1091
|
||||
#: ../js/ui/lookingGlass.js:680 ../src/gvc/gvc-mixer-control.c:1091
|
||||
msgid "Disabled"
|
||||
msgstr "מנוטרל"
|
||||
|
||||
#: ../js/ui/lookingGlass.js:635
|
||||
#: ../js/ui/lookingGlass.js:682
|
||||
msgid "Error"
|
||||
msgstr "שגיאה"
|
||||
|
||||
#: ../js/ui/lookingGlass.js:637
|
||||
#: ../js/ui/lookingGlass.js:684
|
||||
msgid "Out of date"
|
||||
msgstr "לא בתוקף"
|
||||
|
||||
#: ../js/ui/lookingGlass.js:662
|
||||
#: ../js/ui/lookingGlass.js:709
|
||||
msgid "View Source"
|
||||
msgstr "צפייה במקור"
|
||||
|
||||
#: ../js/ui/lookingGlass.js:668
|
||||
#: ../js/ui/lookingGlass.js:715
|
||||
msgid "Web Page"
|
||||
msgstr "דף אינטרנט"
|
||||
|
||||
#: ../js/ui/messageTray.js:1027
|
||||
#: ../js/ui/messageTray.js:1115
|
||||
msgid "Open"
|
||||
msgstr "פתיחה"
|
||||
|
||||
#: ../js/ui/messageTray.js:2197
|
||||
#: ../js/ui/messageTray.js:2286
|
||||
msgid "System Information"
|
||||
msgstr "פרטי המערכת"
|
||||
|
||||
@ -571,18 +571,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:532
|
||||
#, 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
|
||||
#. Translators: If there is no suitable word for "Activities"
|
||||
#. in your language, you can use the word for "Overview".
|
||||
#: ../js/ui/panel.js:568
|
||||
msgid "Activities"
|
||||
msgstr "פעילויות"
|
||||
|
||||
#: ../js/ui/panel.js:1015
|
||||
#: ../js/ui/panel.js:951
|
||||
msgid "Top Bar"
|
||||
msgstr "הסרגל העליון"
|
||||
|
||||
@ -640,52 +640,53 @@ msgstr "toggle-switch-intl"
|
||||
msgid "Please enter a command:"
|
||||
msgstr "נא להזין פקודה:"
|
||||
|
||||
#: ../js/ui/searchDisplay.js:311
|
||||
#: ../js/ui/searchDisplay.js:318
|
||||
msgid "Searching..."
|
||||
msgstr "בחיפוש..."
|
||||
|
||||
#: ../js/ui/searchDisplay.js:325
|
||||
#: ../js/ui/searchDisplay.js:332
|
||||
msgid "No matching results."
|
||||
msgstr "אין תוצאות תואמות."
|
||||
|
||||
#: ../js/ui/statusMenu.js:159 ../js/ui/statusMenu.js:161
|
||||
#: ../js/ui/statusMenu.js:226
|
||||
#: ../js/ui/statusMenu.js:192 ../js/ui/statusMenu.js:196
|
||||
#: ../js/ui/statusMenu.js:262
|
||||
msgid "Power Off..."
|
||||
msgstr "כיבוי..."
|
||||
|
||||
#: ../js/ui/statusMenu.js:161 ../js/ui/statusMenu.js:225
|
||||
#: ../js/ui/statusMenu.js:194 ../js/ui/statusMenu.js:196
|
||||
#: ../js/ui/statusMenu.js:261
|
||||
msgid "Suspend"
|
||||
msgstr "השהיה"
|
||||
|
||||
#: ../js/ui/statusMenu.js:182
|
||||
#: ../js/ui/statusMenu.js:217
|
||||
msgid "Available"
|
||||
msgstr "פנוי"
|
||||
|
||||
#: ../js/ui/statusMenu.js:187
|
||||
#: ../js/ui/statusMenu.js:222
|
||||
msgid "Busy"
|
||||
msgstr "עסוק"
|
||||
|
||||
#: ../js/ui/statusMenu.js:195
|
||||
#: ../js/ui/statusMenu.js:230
|
||||
msgid "My Account"
|
||||
msgstr "החשבון שלי"
|
||||
|
||||
#: ../js/ui/statusMenu.js:199
|
||||
#: ../js/ui/statusMenu.js:234
|
||||
msgid "System Settings"
|
||||
msgstr "הגדרות המערכת"
|
||||
|
||||
#: ../js/ui/statusMenu.js:206
|
||||
#: ../js/ui/statusMenu.js:242
|
||||
msgid "Lock Screen"
|
||||
msgstr "נעילת המסך"
|
||||
|
||||
#: ../js/ui/statusMenu.js:211
|
||||
#: ../js/ui/statusMenu.js:247
|
||||
msgid "Switch User"
|
||||
msgstr "החלפת משתמש"
|
||||
|
||||
#: ../js/ui/statusMenu.js:216
|
||||
#: ../js/ui/statusMenu.js:252
|
||||
msgid "Log Out..."
|
||||
msgstr "ניתוק..."
|
||||
|
||||
#: ../js/ui/status/accessibility.js:59
|
||||
#: ../js/ui/status/accessibility.js:60
|
||||
msgid "Zoom"
|
||||
msgstr "תקריב"
|
||||
|
||||
@ -695,41 +696,41 @@ msgstr "תקריב"
|
||||
#. let screenKeyboard = this._buildItem(_("Screen Keyboard"), APPLICATIONS_SCHEMA,
|
||||
#. 'screen-keyboard-enabled');
|
||||
#. this.menu.addMenuItem(screenKeyboard);
|
||||
#: ../js/ui/status/accessibility.js:74
|
||||
#: ../js/ui/status/accessibility.js:75
|
||||
msgid "Visual Alerts"
|
||||
msgstr "התראות חזותיות"
|
||||
|
||||
#: ../js/ui/status/accessibility.js:77
|
||||
#: ../js/ui/status/accessibility.js:78
|
||||
msgid "Sticky Keys"
|
||||
msgstr "מקשים דביקים"
|
||||
|
||||
#: ../js/ui/status/accessibility.js:80
|
||||
#: ../js/ui/status/accessibility.js:81
|
||||
msgid "Slow Keys"
|
||||
msgstr "מקשים אטיים"
|
||||
|
||||
#: ../js/ui/status/accessibility.js:83
|
||||
#: ../js/ui/status/accessibility.js:84
|
||||
msgid "Bounce Keys"
|
||||
msgstr "מקשים קופצים"
|
||||
|
||||
#: ../js/ui/status/accessibility.js:86
|
||||
#: ../js/ui/status/accessibility.js:87
|
||||
msgid "Mouse Keys"
|
||||
msgstr "מקשי עכבר"
|
||||
|
||||
#: ../js/ui/status/accessibility.js:90
|
||||
#: ../js/ui/status/accessibility.js:91
|
||||
msgid "Universal Access Settings"
|
||||
msgstr "הגדרות גישה אוניברסלית"
|
||||
|
||||
#: ../js/ui/status/accessibility.js:143
|
||||
#: ../js/ui/status/accessibility.js:145
|
||||
msgid "High Contrast"
|
||||
msgstr "ניגודיות גבוהה"
|
||||
|
||||
#: ../js/ui/status/accessibility.js:180
|
||||
#: ../js/ui/status/accessibility.js:182
|
||||
msgid "Large Text"
|
||||
msgstr "טקסט גדול"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:39 ../js/ui/status/bluetooth.js:261
|
||||
#: ../js/ui/status/bluetooth.js:355 ../js/ui/status/bluetooth.js:389
|
||||
#: ../js/ui/status/bluetooth.js:429 ../js/ui/status/bluetooth.js:462
|
||||
#: ../js/ui/status/bluetooth.js:39 ../js/ui/status/bluetooth.js:270
|
||||
#: ../js/ui/status/bluetooth.js:364 ../js/ui/status/bluetooth.js:398
|
||||
#: ../js/ui/status/bluetooth.js:438 ../js/ui/status/bluetooth.js:471
|
||||
msgid "Bluetooth"
|
||||
msgstr "Bluetooth"
|
||||
|
||||
@ -749,102 +750,115 @@ msgstr "הגדרת התקן חדש..."
|
||||
msgid "Bluetooth Settings"
|
||||
msgstr "הגדרות Bluetooth"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:212
|
||||
#. TRANSLATORS: this means that bluetooth was disabled by hardware rfkill
|
||||
#: ../js/ui/status/bluetooth.js:116
|
||||
msgid "hardware disabled"
|
||||
msgstr "מנוטרל חומרתית"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:217
|
||||
msgid "Connection"
|
||||
msgstr "חיבור"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:248
|
||||
#: ../js/ui/status/bluetooth.js:226 ../js/ui/status/network.js:493
|
||||
msgid "disconnecting..."
|
||||
msgstr "בהליכי ניתוק..."
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:239 ../js/ui/status/network.js:499
|
||||
msgid "connecting..."
|
||||
msgstr "בהתחברות..."
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:257
|
||||
msgid "Send Files..."
|
||||
msgstr "שליחת קבצים..."
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:253
|
||||
#: ../js/ui/status/bluetooth.js:262
|
||||
msgid "Browse Files..."
|
||||
msgstr "עיון בקבצים..."
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:262
|
||||
#: ../js/ui/status/bluetooth.js:271
|
||||
msgid "Error browsing device"
|
||||
msgstr "שגיאה בעיון בהתקן"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:263
|
||||
#: ../js/ui/status/bluetooth.js:272
|
||||
#, c-format
|
||||
msgid "The requested device cannot be browsed, error is '%s'"
|
||||
msgstr "לא ניתן לעיין בהתקן הנבחר, השגיאה היא '%s'"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:271
|
||||
#: ../js/ui/status/bluetooth.js:280
|
||||
msgid "Keyboard Settings"
|
||||
msgstr "הגדרות מקלדת"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:276
|
||||
#: ../js/ui/status/bluetooth.js:285
|
||||
msgid "Mouse Settings"
|
||||
msgstr "הגדרות עכבר"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:283 ../js/ui/status/volume.js:63
|
||||
#: ../js/ui/status/bluetooth.js:292 ../js/ui/status/volume.js:64
|
||||
msgid "Sound Settings"
|
||||
msgstr "הגדרות שמע"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:390
|
||||
#: ../js/ui/status/bluetooth.js:399
|
||||
#, c-format
|
||||
msgid "Authorization request from %s"
|
||||
msgstr "בקשת אישור מאת %s"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:396
|
||||
#: ../js/ui/status/bluetooth.js:405
|
||||
#, c-format
|
||||
msgid "Device %s wants access to the service '%s'"
|
||||
msgstr "ההתקן %s מעוניין לגשת אל השירות '%s'"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:398
|
||||
#: ../js/ui/status/bluetooth.js:407
|
||||
msgid "Always grant access"
|
||||
msgstr "תמיד להעניק גישה"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:399
|
||||
#: ../js/ui/status/bluetooth.js:408
|
||||
msgid "Grant this time only"
|
||||
msgstr "הענקת גישה הפעם בלבד"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:400
|
||||
#: ../js/ui/status/bluetooth.js:409 ../js/ui/telepathyClient.js:954
|
||||
msgid "Reject"
|
||||
msgstr "סירוב"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:430
|
||||
#: ../js/ui/status/bluetooth.js:439
|
||||
#, c-format
|
||||
msgid "Pairing confirmation for %s"
|
||||
msgstr "אישור צימוד עבור %s"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:436 ../js/ui/status/bluetooth.js:470
|
||||
#: ../js/ui/status/bluetooth.js:445 ../js/ui/status/bluetooth.js:479
|
||||
#, c-format
|
||||
msgid "Device %s wants to pair with this computer"
|
||||
msgstr "ההתקן %s מעוניין בצימוד עם מחשב זה"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:437
|
||||
#: ../js/ui/status/bluetooth.js:446
|
||||
#, c-format
|
||||
msgid "Please confirm whether the PIN '%s' matches the one on the device."
|
||||
msgstr "נא לאשר האם קוד ה־PIN '%s' תואם את זה שמופיע בהתקן."
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:439
|
||||
#: ../js/ui/status/bluetooth.js:448
|
||||
msgid "Matches"
|
||||
msgstr "התאמות"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:440
|
||||
#: ../js/ui/status/bluetooth.js:449
|
||||
msgid "Does not match"
|
||||
msgstr "אינו תואם"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:463
|
||||
#: ../js/ui/status/bluetooth.js:472
|
||||
#, c-format
|
||||
msgid "Pairing request for %s"
|
||||
msgstr "בקשת צימוד עבור %s"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:471
|
||||
#: ../js/ui/status/bluetooth.js:480
|
||||
msgid "Please enter the PIN mentioned on the device."
|
||||
msgstr "נא להזין את קוד ה־PIN המוזכר בהתקן."
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:487
|
||||
#: ../js/ui/status/bluetooth.js:496
|
||||
msgid "OK"
|
||||
msgstr "אישור"
|
||||
|
||||
#: ../js/ui/status/keyboard.js:70
|
||||
#: ../js/ui/status/keyboard.js:71
|
||||
msgid "Show Keyboard Layout..."
|
||||
msgstr "הצגת פריסת המקלדת..."
|
||||
|
||||
#: ../js/ui/status/keyboard.js:73
|
||||
#: ../js/ui/status/keyboard.js:75
|
||||
msgid "Localization Settings"
|
||||
msgstr "הגדרות אזוריות"
|
||||
|
||||
@ -853,158 +867,150 @@ msgid "<unknown>"
|
||||
msgstr "<לא ידוע>"
|
||||
|
||||
#. Translators: this indicates that wireless or wwan is disabled by hardware killswitch
|
||||
#: ../js/ui/status/network.js:340
|
||||
#: ../js/ui/status/network.js:292
|
||||
msgid "disabled"
|
||||
msgstr "מנוטרל"
|
||||
|
||||
#. 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)
|
||||
#: ../js/ui/status/network.js:535
|
||||
#: ../js/ui/status/network.js:491
|
||||
msgid "unmanaged"
|
||||
msgstr "לא מנוהל"
|
||||
|
||||
#: ../js/ui/status/network.js:537
|
||||
msgid "disconnecting..."
|
||||
msgstr "בהליכי ניתוק..."
|
||||
|
||||
#: ../js/ui/status/network.js:543
|
||||
msgid "connecting..."
|
||||
msgstr "בהתחברות..."
|
||||
|
||||
#. Translators: this is for network connections that require some kind of key or password
|
||||
#: ../js/ui/status/network.js:546
|
||||
#: ../js/ui/status/network.js:502
|
||||
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:556
|
||||
#: ../js/ui/status/network.js:512
|
||||
msgid "firmware missing"
|
||||
msgstr "הקושחה חסרה"
|
||||
|
||||
#. Translators: this is for wired network devices that are physically disconnected
|
||||
#: ../js/ui/status/network.js:563
|
||||
#: ../js/ui/status/network.js:519
|
||||
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:568
|
||||
#: ../js/ui/status/network.js:524
|
||||
msgid "unavailable"
|
||||
msgstr "לא זמין"
|
||||
|
||||
#: ../js/ui/status/network.js:570
|
||||
#: ../js/ui/status/network.js:526
|
||||
msgid "connection failed"
|
||||
msgstr "החיבור נכשל"
|
||||
|
||||
#: ../js/ui/status/network.js:582 ../js/ui/status/network.js:1507
|
||||
msgid "More..."
|
||||
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:651 ../js/ui/status/network.js:1460
|
||||
#: ../js/ui/status/network.js:618 ../js/ui/status/network.js:1444
|
||||
msgid "Connected (private)"
|
||||
msgstr "מחובר (פרטי)"
|
||||
|
||||
#: ../js/ui/status/network.js:736
|
||||
#: ../js/ui/status/network.js:703
|
||||
msgid "Auto Ethernet"
|
||||
msgstr "אתרנט אוטומטי"
|
||||
|
||||
#: ../js/ui/status/network.js:804
|
||||
#: ../js/ui/status/network.js:771
|
||||
msgid "Auto broadband"
|
||||
msgstr "פס רחב אוטומטי"
|
||||
|
||||
#: ../js/ui/status/network.js:807
|
||||
#: ../js/ui/status/network.js:774
|
||||
msgid "Auto dial-up"
|
||||
msgstr "חיוג אוטומטי"
|
||||
|
||||
#. TRANSLATORS: this the automatic wireless connection name (including the network name)
|
||||
#: ../js/ui/status/network.js:931 ../js/ui/status/network.js:1472
|
||||
#: ../js/ui/status/network.js:898 ../js/ui/status/network.js:1456
|
||||
#, c-format
|
||||
msgid "Auto %s"
|
||||
msgstr "%s אוטומטי"
|
||||
|
||||
#: ../js/ui/status/network.js:933
|
||||
#: ../js/ui/status/network.js:900
|
||||
msgid "Auto bluetooth"
|
||||
msgstr "Bluetooth אוטומטי"
|
||||
|
||||
#: ../js/ui/status/network.js:1474
|
||||
#: ../js/ui/status/network.js:1458
|
||||
msgid "Auto wireless"
|
||||
msgstr "אלחוטי אוטומטי"
|
||||
|
||||
#: ../js/ui/status/network.js:1522
|
||||
msgid "More..."
|
||||
msgstr "עוד..."
|
||||
|
||||
#: ../js/ui/status/network.js:1564
|
||||
#: ../js/ui/status/network.js:1550
|
||||
msgid "Enable networking"
|
||||
msgstr "הפעלת תכונת הרשת"
|
||||
|
||||
#: ../js/ui/status/network.js:1576
|
||||
#: ../js/ui/status/network.js:1562
|
||||
msgid "Wired"
|
||||
msgstr "קווי"
|
||||
|
||||
#: ../js/ui/status/network.js:1587
|
||||
#: ../js/ui/status/network.js:1573
|
||||
msgid "Wireless"
|
||||
msgstr "אלחוטי"
|
||||
|
||||
#: ../js/ui/status/network.js:1597
|
||||
#: ../js/ui/status/network.js:1583
|
||||
msgid "Mobile broadband"
|
||||
msgstr "פס־רחב נייד"
|
||||
|
||||
#: ../js/ui/status/network.js:1607
|
||||
#: ../js/ui/status/network.js:1593
|
||||
msgid "VPN Connections"
|
||||
msgstr "חיבורי VPN"
|
||||
|
||||
#: ../js/ui/status/network.js:1619
|
||||
#: ../js/ui/status/network.js:1605
|
||||
msgid "Network Settings"
|
||||
msgstr "הגדרות הרשת"
|
||||
|
||||
#: ../js/ui/status/network.js:1910
|
||||
#: ../js/ui/status/network.js:1897
|
||||
#, c-format
|
||||
msgid "You're now connected to mobile broadband connection '%s'"
|
||||
msgstr "כרגע ישנו חיבור בינך ובין רשת הפס הרחב הניידת '%s'"
|
||||
|
||||
#: ../js/ui/status/network.js:1914
|
||||
#: ../js/ui/status/network.js:1901
|
||||
#, c-format
|
||||
msgid "You're now connected to wireless network '%s'"
|
||||
msgstr "כרגע ישנו חיבור בינך ובין הרשת האלחוטית '%s'"
|
||||
|
||||
#: ../js/ui/status/network.js:1918
|
||||
#: ../js/ui/status/network.js:1905
|
||||
#, c-format
|
||||
msgid "You're now connected to wired network '%s'"
|
||||
msgstr "כרגע ישנו חיבור בינך ובין הרשת הקווית '%s'"
|
||||
|
||||
#: ../js/ui/status/network.js:1922
|
||||
#: ../js/ui/status/network.js:1909
|
||||
#, c-format
|
||||
msgid "You're now connected to VPN network '%s'"
|
||||
msgstr "כרגע ישנו חיבור בינך ובין רשת ה־VPN '%s'"
|
||||
|
||||
#: ../js/ui/status/network.js:1927
|
||||
#: ../js/ui/status/network.js:1914
|
||||
#, c-format
|
||||
msgid "You're now connected to '%s'"
|
||||
msgstr "כעת ישנו חיבור בינך ובין '%s'"
|
||||
|
||||
#: ../js/ui/status/network.js:1935
|
||||
#: ../js/ui/status/network.js:1922
|
||||
msgid "Connection established"
|
||||
msgstr "ההתחברות הצליחה"
|
||||
|
||||
#: ../js/ui/status/network.js:2061
|
||||
#: ../js/ui/status/network.js:2048
|
||||
msgid "Networking is disabled"
|
||||
msgstr "תכונת הרשת מנוטרלת"
|
||||
|
||||
#: ../js/ui/status/network.js:2186
|
||||
#: ../js/ui/status/network.js:2173
|
||||
msgid "Network Manager"
|
||||
msgstr "מנהל הרשתות"
|
||||
|
||||
#: ../js/ui/status/power.js:82
|
||||
#: ../js/ui/status/power.js:83
|
||||
msgid "Power Settings"
|
||||
msgstr "הגדרות צריכת החשמל"
|
||||
|
||||
#. 0 is reported when UPower does not have enough data
|
||||
#. to estimate battery life
|
||||
#: ../js/ui/status/power.js:108
|
||||
#: ../js/ui/status/power.js:109
|
||||
msgid "Estimating..."
|
||||
msgstr "מתבצע שיערוך..."
|
||||
|
||||
#: ../js/ui/status/power.js:115
|
||||
#: ../js/ui/status/power.js:116
|
||||
#, c-format
|
||||
msgid "%d hour remaining"
|
||||
msgid_plural "%d hours remaining"
|
||||
@ -1013,26 +1019,26 @@ msgstr[1] "נותרו %d שעות"
|
||||
msgstr[2] "נותרו שעתיים"
|
||||
|
||||
#. TRANSLATORS: this is a time string, as in "%d hours %d minutes remaining"
|
||||
#: ../js/ui/status/power.js:118
|
||||
#: ../js/ui/status/power.js:119
|
||||
#, c-format
|
||||
msgid "%d %s %d %s remaining"
|
||||
msgstr "%d %s %d %s נותרו"
|
||||
|
||||
#: ../js/ui/status/power.js:120
|
||||
#: ../js/ui/status/power.js:121
|
||||
msgid "hour"
|
||||
msgid_plural "hours"
|
||||
msgstr[0] "שעה"
|
||||
msgstr[1] "שעות"
|
||||
msgstr[2] "שעתיים"
|
||||
|
||||
#: ../js/ui/status/power.js:120
|
||||
#: ../js/ui/status/power.js:121
|
||||
msgid "minute"
|
||||
msgid_plural "minutes"
|
||||
msgstr[0] "דקה"
|
||||
msgstr[1] "דקות"
|
||||
msgstr[2] "דקות"
|
||||
|
||||
#: ../js/ui/status/power.js:123
|
||||
#: ../js/ui/status/power.js:124
|
||||
#, c-format
|
||||
msgid "%d minute remaining"
|
||||
msgid_plural "%d minutes remaining"
|
||||
@ -1040,78 +1046,90 @@ msgstr[0] "דקה אחת נותרה"
|
||||
msgstr[1] "%d דקות נותרו"
|
||||
msgstr[2] "שתי דקות נותרו"
|
||||
|
||||
#: ../js/ui/status/power.js:225
|
||||
#: ../js/ui/status/power.js:216
|
||||
msgid "AC adapter"
|
||||
msgstr "מתאם חשמל"
|
||||
|
||||
#: ../js/ui/status/power.js:227
|
||||
#: ../js/ui/status/power.js:218
|
||||
msgid "Laptop battery"
|
||||
msgstr "סוללת נייד"
|
||||
|
||||
#: ../js/ui/status/power.js:229
|
||||
#: ../js/ui/status/power.js:220
|
||||
msgid "UPS"
|
||||
msgstr "אל־פסק"
|
||||
|
||||
#: ../js/ui/status/power.js:231
|
||||
#: ../js/ui/status/power.js:222
|
||||
msgid "Monitor"
|
||||
msgstr "צג"
|
||||
|
||||
#: ../js/ui/status/power.js:233
|
||||
#: ../js/ui/status/power.js:224
|
||||
msgid "Mouse"
|
||||
msgstr "עכבר"
|
||||
|
||||
#: ../js/ui/status/power.js:235
|
||||
#: ../js/ui/status/power.js:226
|
||||
msgid "Keyboard"
|
||||
msgstr "מקלדת"
|
||||
|
||||
#: ../js/ui/status/power.js:237
|
||||
#: ../js/ui/status/power.js:228
|
||||
msgid "PDA"
|
||||
msgstr "מחשב כף יד"
|
||||
|
||||
#: ../js/ui/status/power.js:239
|
||||
#: ../js/ui/status/power.js:230
|
||||
msgid "Cell phone"
|
||||
msgstr "טלפון סלולרי"
|
||||
|
||||
#: ../js/ui/status/power.js:241
|
||||
#: ../js/ui/status/power.js:232
|
||||
msgid "Media player"
|
||||
msgstr "נגן מדיה"
|
||||
|
||||
#: ../js/ui/status/power.js:243
|
||||
#: ../js/ui/status/power.js:234
|
||||
msgid "Tablet"
|
||||
msgstr "טבלת שליטה"
|
||||
|
||||
#: ../js/ui/status/power.js:245
|
||||
#: ../js/ui/status/power.js:236
|
||||
msgid "Computer"
|
||||
msgstr "מחשב"
|
||||
|
||||
#: ../js/ui/status/power.js:247 ../src/shell-app-system.c:1088
|
||||
#: ../js/ui/status/power.js:238 ../src/shell-app-system.c:1088
|
||||
msgid "Unknown"
|
||||
msgstr "לא ידוע"
|
||||
|
||||
#: ../js/ui/status/volume.js:42
|
||||
#: ../js/ui/status/volume.js:43
|
||||
msgid "Volume"
|
||||
msgstr "עצמה"
|
||||
|
||||
#: ../js/ui/status/volume.js:55
|
||||
#: ../js/ui/status/volume.js:56
|
||||
msgid "Microphone"
|
||||
msgstr "מיקרופון"
|
||||
|
||||
#: ../js/ui/telepathyClient.js:339
|
||||
#. We got the TpContact
|
||||
#. FIXME: We don't have a 'chat room' icon (bgo #653737) use
|
||||
#. system-users for now as Empathy does.
|
||||
#: ../js/ui/telepathyClient.js:222
|
||||
msgid "Invitation"
|
||||
msgstr "הזמנה"
|
||||
|
||||
#. We got the TpContact
|
||||
#: ../js/ui/telepathyClient.js:285
|
||||
msgid "Call"
|
||||
msgstr "התקשרות"
|
||||
|
||||
#: ../js/ui/telepathyClient.js:541
|
||||
#, c-format
|
||||
msgid "%s is online."
|
||||
msgstr "%s התחבר/ה."
|
||||
|
||||
#: ../js/ui/telepathyClient.js:344
|
||||
#: ../js/ui/telepathyClient.js:546
|
||||
#, c-format
|
||||
msgid "%s is offline."
|
||||
msgstr "%s התנתק/ה."
|
||||
|
||||
#: ../js/ui/telepathyClient.js:347
|
||||
#: ../js/ui/telepathyClient.js:549
|
||||
#, c-format
|
||||
msgid "%s is away."
|
||||
msgstr "'%s' מרוחק/ת."
|
||||
|
||||
#: ../js/ui/telepathyClient.js:350
|
||||
#: ../js/ui/telepathyClient.js:552
|
||||
#, c-format
|
||||
msgid "%s is busy."
|
||||
msgstr "%s עסוק/ה."
|
||||
@ -1119,18 +1137,57 @@ 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:492
|
||||
#: ../js/ui/telepathyClient.js:741
|
||||
#, 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:537
|
||||
#: ../js/ui/telepathyClient.js:791
|
||||
#, c-format
|
||||
msgid "%s is now known as %s"
|
||||
msgstr "השם של %s הוחלף ל־%s"
|
||||
|
||||
#. translators: argument is a room name like
|
||||
#. * room@jabber.org for example.
|
||||
#: ../js/ui/telepathyClient.js:898
|
||||
#, c-format
|
||||
msgid "Invitation to %s"
|
||||
msgstr "הזמנה ל־%s"
|
||||
|
||||
#. 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.
|
||||
#: ../js/ui/telepathyClient.js:906
|
||||
#, c-format
|
||||
msgid "%s is inviting you to join %s"
|
||||
msgstr "הוזמנת על ידי %s להצטרף אל %s"
|
||||
|
||||
#: ../js/ui/telepathyClient.js:908
|
||||
msgid "Decline"
|
||||
msgstr "דחייה"
|
||||
|
||||
#: ../js/ui/telepathyClient.js:909
|
||||
msgid "Accept"
|
||||
msgstr "אישור"
|
||||
|
||||
#. translators: argument is a contact name like Alice for example.
|
||||
#: ../js/ui/telepathyClient.js:942
|
||||
#, c-format
|
||||
msgid "Video call from %s"
|
||||
msgstr "שיחת וידאו מאת %s"
|
||||
|
||||
#. translators: argument is a contact name like Alice for example.
|
||||
#: ../js/ui/telepathyClient.js:945
|
||||
#, c-format
|
||||
msgid "Call from %s"
|
||||
msgstr "שיחה מאת %s"
|
||||
|
||||
#: ../js/ui/telepathyClient.js:955
|
||||
msgid "Answer"
|
||||
msgstr "מענה"
|
||||
|
||||
#. Translators: this is the text displayed
|
||||
#. in the search entry when no search is
|
||||
#. active; it should not exceed ~30
|
||||
@ -1139,7 +1196,7 @@ msgstr "השם של %s הוחלף ל־%s"
|
||||
msgid "Type to search..."
|
||||
msgstr "יש להקליד כדי לחפש..."
|
||||
|
||||
#: ../js/ui/viewSelector.js:140 ../src/shell-util.c:254
|
||||
#: ../js/ui/viewSelector.js:140 ../src/shell-util.c:257
|
||||
msgid "Search"
|
||||
msgstr "חיפוש"
|
||||
|
||||
@ -1177,7 +1234,7 @@ msgstr[2] "2 קלטים"
|
||||
msgid "System Sounds"
|
||||
msgstr "צלילי מערכת"
|
||||
|
||||
#: ../src/main.c:445
|
||||
#: ../src/main.c:466
|
||||
msgid "Print version"
|
||||
msgstr "Print version"
|
||||
|
||||
@ -1198,13 +1255,13 @@ msgstr "בררת מחדל"
|
||||
msgid "Authentication dialog was dismissed by the user"
|
||||
msgstr "המשתמש בחר להתעלם מתיבת דו־שיח האימות"
|
||||
|
||||
#: ../src/shell-util.c:93
|
||||
#: ../src/shell-util.c:96
|
||||
msgid "Home Folder"
|
||||
msgstr "תיקיית הבית"
|
||||
|
||||
#. Translators: this is the same string as the one found in
|
||||
#. * nautilus
|
||||
#: ../src/shell-util.c:108
|
||||
#: ../src/shell-util.c:111
|
||||
msgid "File System"
|
||||
msgstr "מערכת הקבצים"
|
||||
|
||||
@ -1213,7 +1270,7 @@ msgstr "מערכת הקבצים"
|
||||
#. * example, "Trash: some-directory". It means that the
|
||||
#. * directory called "some-directory" is in the trash.
|
||||
#.
|
||||
#: ../src/shell-util.c:304
|
||||
#: ../src/shell-util.c:307
|
||||
#, c-format
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s: %2$s"
|
||||
|
221
po/nb.po
221
po/nb.po
@ -6,10 +6,10 @@
|
||||
# Torstein Adolf Winterseth <kvikende@fsfe.org>, 2010.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell 2.91.x\n"
|
||||
"Project-Id-Version: gnome-shell 3.1.x\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-06-28 22:55+0200\n"
|
||||
"PO-Revision-Date: 2011-06-28 22:56+0200\n"
|
||||
"POT-Creation-Date: 2011-07-18 13:48+0200\n"
|
||||
"PO-Revision-Date: 2011-07-18 13:50+0200\n"
|
||||
"Last-Translator: Kjartan Maraas <kmaraas@gnome.org>\n"
|
||||
"Language-Team: Norwegian Bokmål <i18n-nb@lister.ping.uio.no>\n"
|
||||
"Language: \n"
|
||||
@ -17,7 +17,6 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: Lokalize 1.1\n"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:1
|
||||
msgid "GNOME Shell"
|
||||
@ -52,17 +51,20 @@ msgid ""
|
||||
"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."
|
||||
msgstr "GNOME Shell-utvidelser har en uuid-egenskap. Denne nøkkelen lister utvidelser som ikke bør lastes. disabled-extensions overstyrer denne innstillingen for utvidelser som finnes i begge listene."
|
||||
msgstr ""
|
||||
"GNOME Shell-utvidelser har en uuid-egenskap. Denne nøkkelen lister "
|
||||
"utvidelser som ikke bør lastes. disabled-extensions overstyrer denne "
|
||||
"innstillingen for utvidelser som finnes i begge listene."
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:6
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
"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."
|
||||
msgstr ""
|
||||
"GNOME Shell-utvidelser har en uuid-egenskap. Denne nøkkelen lister "
|
||||
"utvidelser som ikke bør lastes."
|
||||
"utvidelser som ikke bør lastes. Denne innstillingen overstyrer enabled-"
|
||||
"extensions for utvidelser som finnes i begge listene."
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:7
|
||||
msgid "History for command (Alt-F2) dialog"
|
||||
@ -101,9 +103,7 @@ msgid ""
|
||||
"'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 ""
|
||||
"Setter GStreamer-rør som brukes til å kode opptak. Den følger syntaksen som "
|
||||
"brukes for gst-launch."
|
||||
msgstr "Setter GStreamer-rør som brukes til å kode opptak. Den følger syntaksen som brukes for gst-launch."
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:15
|
||||
msgid "Show date in clock"
|
||||
@ -191,27 +191,27 @@ msgid "Execution of '%s' failed:"
|
||||
msgstr "Kjøring av «%s» feilet:"
|
||||
|
||||
#. Translators: Filter to display all applications
|
||||
#: ../js/ui/appDisplay.js:258
|
||||
#: ../js/ui/appDisplay.js:252
|
||||
msgid "All"
|
||||
msgstr "Alle"
|
||||
|
||||
#: ../js/ui/appDisplay.js:357
|
||||
#: ../js/ui/appDisplay.js:359
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "PROGRAMMER"
|
||||
|
||||
#: ../js/ui/appDisplay.js:383
|
||||
#: ../js/ui/appDisplay.js:385
|
||||
msgid "SETTINGS"
|
||||
msgstr "INNSTILLINGER"
|
||||
|
||||
#: ../js/ui/appDisplay.js:656
|
||||
#: ../js/ui/appDisplay.js:658
|
||||
msgid "New Window"
|
||||
msgstr "Nytt vindu"
|
||||
|
||||
#: ../js/ui/appDisplay.js:659
|
||||
#: ../js/ui/appDisplay.js:661
|
||||
msgid "Remove from Favorites"
|
||||
msgstr "Fjern fra favoritter"
|
||||
|
||||
#: ../js/ui/appDisplay.js:660
|
||||
#: ../js/ui/appDisplay.js:662
|
||||
msgid "Add to Favorites"
|
||||
msgstr "Legg til i favoritter"
|
||||
|
||||
@ -344,13 +344,13 @@ msgid "Nothing Scheduled"
|
||||
msgstr "Ingenting planlagt"
|
||||
|
||||
#. Translators: Shown on calendar heading when selected day occurs on current year
|
||||
#: ../js/ui/calendar.js:717 ../js/ui/telepathyClient.js:568
|
||||
#: ../js/ui/calendar.js:717 ../js/ui/telepathyClient.js:749
|
||||
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:720 ../js/ui/telepathyClient.js:571
|
||||
#: ../js/ui/calendar.js:720 ../js/ui/telepathyClient.js:752
|
||||
msgctxt "calendar heading"
|
||||
msgid "%A, %B %d, %Y"
|
||||
msgstr "%A %B %d, %Y"
|
||||
@ -371,7 +371,7 @@ msgstr "Denne uken"
|
||||
msgid "Next week"
|
||||
msgstr "Neste uke"
|
||||
|
||||
#: ../js/ui/dash.js:172 ../js/ui/messageTray.js:1044
|
||||
#: ../js/ui/dash.js:172 ../js/ui/messageTray.js:1122
|
||||
msgid "Remove"
|
||||
msgstr "Fjern"
|
||||
|
||||
@ -535,11 +535,11 @@ msgstr "Vis kildekode"
|
||||
msgid "Web Page"
|
||||
msgstr "Nettside"
|
||||
|
||||
#: ../js/ui/messageTray.js:1037
|
||||
#: ../js/ui/messageTray.js:1115
|
||||
msgid "Open"
|
||||
msgstr "Åpne"
|
||||
|
||||
#: ../js/ui/messageTray.js:2207
|
||||
#: ../js/ui/messageTray.js:2286
|
||||
msgid "System Information"
|
||||
msgstr "Systeminformasjon"
|
||||
|
||||
@ -562,18 +562,18 @@ msgid "Dash"
|
||||
msgstr "Favoritter"
|
||||
|
||||
#. TODO - _quit() doesn't really work on apps in state STARTING yet
|
||||
#: ../js/ui/panel.js:533
|
||||
#: ../js/ui/panel.js:532
|
||||
#, c-format
|
||||
msgid "Quit %s"
|
||||
msgstr "Avslutt %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
|
||||
#. Translators: If there is no suitable word for "Activities"
|
||||
#. in your language, you can use the word for "Overview".
|
||||
#: ../js/ui/panel.js:568
|
||||
msgid "Activities"
|
||||
msgstr "Aktiviteter"
|
||||
|
||||
#: ../js/ui/panel.js:1013
|
||||
#: ../js/ui/panel.js:951
|
||||
msgid "Top Bar"
|
||||
msgstr "Topp-panel"
|
||||
|
||||
@ -639,41 +639,41 @@ msgstr "Søker …"
|
||||
msgid "No matching results."
|
||||
msgstr "Ingen treff."
|
||||
|
||||
#: ../js/ui/statusMenu.js:202 ../js/ui/statusMenu.js:206
|
||||
#: ../js/ui/statusMenu.js:272
|
||||
#: ../js/ui/statusMenu.js:192 ../js/ui/statusMenu.js:196
|
||||
#: ../js/ui/statusMenu.js:262
|
||||
msgid "Power Off..."
|
||||
msgstr "Slå av …"
|
||||
|
||||
#: ../js/ui/statusMenu.js:204 ../js/ui/statusMenu.js:206
|
||||
#: ../js/ui/statusMenu.js:271
|
||||
#: ../js/ui/statusMenu.js:194 ../js/ui/statusMenu.js:196
|
||||
#: ../js/ui/statusMenu.js:261
|
||||
msgid "Suspend"
|
||||
msgstr "Hvilemodus"
|
||||
|
||||
#: ../js/ui/statusMenu.js:227
|
||||
#: ../js/ui/statusMenu.js:217
|
||||
msgid "Available"
|
||||
msgstr "Tilgjengelig"
|
||||
|
||||
#: ../js/ui/statusMenu.js:232
|
||||
#: ../js/ui/statusMenu.js:222
|
||||
msgid "Busy"
|
||||
msgstr "Opptatt"
|
||||
|
||||
#: ../js/ui/statusMenu.js:240
|
||||
#: ../js/ui/statusMenu.js:230
|
||||
msgid "My Account"
|
||||
msgstr "Min konto"
|
||||
|
||||
#: ../js/ui/statusMenu.js:244
|
||||
#: ../js/ui/statusMenu.js:234
|
||||
msgid "System Settings"
|
||||
msgstr "Systeminnstillinger"
|
||||
|
||||
#: ../js/ui/statusMenu.js:252
|
||||
#: ../js/ui/statusMenu.js:242
|
||||
msgid "Lock Screen"
|
||||
msgstr "Lås skjerm"
|
||||
|
||||
#: ../js/ui/statusMenu.js:257
|
||||
#: ../js/ui/statusMenu.js:247
|
||||
msgid "Switch User"
|
||||
msgstr "Bytt bruker"
|
||||
|
||||
#: ../js/ui/statusMenu.js:262
|
||||
#: ../js/ui/statusMenu.js:252
|
||||
msgid "Log Out..."
|
||||
msgstr "Logg ut …"
|
||||
|
||||
@ -805,7 +805,7 @@ msgstr "Alltid gi tilgang"
|
||||
msgid "Grant this time only"
|
||||
msgstr "Gi tilgang kun denne ene gangen"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:409
|
||||
#: ../js/ui/status/bluetooth.js:409 ../js/ui/telepathyClient.js:954
|
||||
msgid "Reject"
|
||||
msgstr "Avvis"
|
||||
|
||||
@ -894,13 +894,13 @@ msgstr "ikke tilgjengelig"
|
||||
msgid "connection failed"
|
||||
msgstr "tilkobling feilet"
|
||||
|
||||
#: ../js/ui/status/network.js:582 ../js/ui/status/network.js:1489
|
||||
#: ../js/ui/status/network.js:582 ../js/ui/status/network.js:1507
|
||||
msgid "More..."
|
||||
msgstr "Mer …"
|
||||
|
||||
#. 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:618 ../js/ui/status/network.js:1427
|
||||
#: ../js/ui/status/network.js:618 ../js/ui/status/network.js:1444
|
||||
msgid "Connected (private)"
|
||||
msgstr "Tilkoblet (privat)"
|
||||
|
||||
@ -917,7 +917,7 @@ msgid "Auto dial-up"
|
||||
msgstr "Automatisk oppringt"
|
||||
|
||||
#. TRANSLATORS: this the automatic wireless connection name (including the network name)
|
||||
#: ../js/ui/status/network.js:898 ../js/ui/status/network.js:1439
|
||||
#: ../js/ui/status/network.js:898 ../js/ui/status/network.js:1456
|
||||
#, c-format
|
||||
msgid "Auto %s"
|
||||
msgstr "Automatisk %s"
|
||||
@ -926,68 +926,68 @@ msgstr "Automatisk %s"
|
||||
msgid "Auto bluetooth"
|
||||
msgstr "Automatisk Bluetooth"
|
||||
|
||||
#: ../js/ui/status/network.js:1441
|
||||
#: ../js/ui/status/network.js:1458
|
||||
msgid "Auto wireless"
|
||||
msgstr "Automatisk trådløst"
|
||||
|
||||
#: ../js/ui/status/network.js:1531
|
||||
#: ../js/ui/status/network.js:1550
|
||||
msgid "Enable networking"
|
||||
msgstr "Slå på nettverk"
|
||||
|
||||
#: ../js/ui/status/network.js:1543
|
||||
#: ../js/ui/status/network.js:1562
|
||||
msgid "Wired"
|
||||
msgstr "Kablet"
|
||||
|
||||
#: ../js/ui/status/network.js:1554
|
||||
#: ../js/ui/status/network.js:1573
|
||||
msgid "Wireless"
|
||||
msgstr "Trådløst"
|
||||
|
||||
#: ../js/ui/status/network.js:1564
|
||||
#: ../js/ui/status/network.js:1583
|
||||
msgid "Mobile broadband"
|
||||
msgstr "Mobilt bredbånd"
|
||||
|
||||
#: ../js/ui/status/network.js:1574
|
||||
#: ../js/ui/status/network.js:1593
|
||||
msgid "VPN Connections"
|
||||
msgstr "VPN-tilkoblinger"
|
||||
|
||||
#: ../js/ui/status/network.js:1586
|
||||
#: ../js/ui/status/network.js:1605
|
||||
msgid "Network Settings"
|
||||
msgstr "Innstillinger for nettverk"
|
||||
|
||||
#: ../js/ui/status/network.js:1878
|
||||
#: ../js/ui/status/network.js:1897
|
||||
#, c-format
|
||||
msgid "You're now connected to mobile broadband connection '%s'"
|
||||
msgstr "Du er nå koblet til mobil bredbåndstilkobling «%s»"
|
||||
|
||||
#: ../js/ui/status/network.js:1882
|
||||
#: ../js/ui/status/network.js:1901
|
||||
#, c-format
|
||||
msgid "You're now connected to wireless network '%s'"
|
||||
msgstr "Du er nå koblet til trådløst nettverk «%s»"
|
||||
|
||||
#: ../js/ui/status/network.js:1886
|
||||
#: ../js/ui/status/network.js:1905
|
||||
#, c-format
|
||||
msgid "You're now connected to wired network '%s'"
|
||||
msgstr "Du er nå koblet til kablet nettverk «%s»"
|
||||
|
||||
#: ../js/ui/status/network.js:1890
|
||||
#: ../js/ui/status/network.js:1909
|
||||
#, c-format
|
||||
msgid "You're now connected to VPN network '%s'"
|
||||
msgstr "Du er nå koblet til virtuelt privat nettverk «%s»"
|
||||
|
||||
#: ../js/ui/status/network.js:1895
|
||||
#: ../js/ui/status/network.js:1914
|
||||
#, c-format
|
||||
msgid "You're now connected to '%s'"
|
||||
msgstr "Du er nå koblet til «%s»"
|
||||
|
||||
#: ../js/ui/status/network.js:1903
|
||||
#: ../js/ui/status/network.js:1922
|
||||
msgid "Connection established"
|
||||
msgstr "Tilkobling etablert"
|
||||
|
||||
#: ../js/ui/status/network.js:2029
|
||||
#: ../js/ui/status/network.js:2048
|
||||
msgid "Networking is disabled"
|
||||
msgstr "Nettverk er slått av"
|
||||
|
||||
#: ../js/ui/status/network.js:2154
|
||||
#: ../js/ui/status/network.js:2173
|
||||
msgid "Network Manager"
|
||||
msgstr "Nettverkshåndtering"
|
||||
|
||||
@ -997,11 +997,11 @@ msgstr "Innstillinger for strøm"
|
||||
|
||||
#. 0 is reported when UPower does not have enough data
|
||||
#. to estimate battery life
|
||||
#: ../js/ui/status/power.js:110
|
||||
#: ../js/ui/status/power.js:109
|
||||
msgid "Estimating..."
|
||||
msgstr "Estimerer …"
|
||||
|
||||
#: ../js/ui/status/power.js:117
|
||||
#: ../js/ui/status/power.js:116
|
||||
#, c-format
|
||||
msgid "%d hour remaining"
|
||||
msgid_plural "%d hours remaining"
|
||||
@ -1009,75 +1009,75 @@ msgstr[0] "%d time gjenstår"
|
||||
msgstr[1] "%d timer gjenstår"
|
||||
|
||||
#. TRANSLATORS: this is a time string, as in "%d hours %d minutes remaining"
|
||||
#: ../js/ui/status/power.js:120
|
||||
#: ../js/ui/status/power.js:119
|
||||
#, c-format
|
||||
msgid "%d %s %d %s remaining"
|
||||
msgstr "%d %s %d %s gjenstår"
|
||||
|
||||
#: ../js/ui/status/power.js:122
|
||||
#: ../js/ui/status/power.js:121
|
||||
msgid "hour"
|
||||
msgid_plural "hours"
|
||||
msgstr[0] "time"
|
||||
msgstr[1] "timer"
|
||||
|
||||
#: ../js/ui/status/power.js:122
|
||||
#: ../js/ui/status/power.js:121
|
||||
msgid "minute"
|
||||
msgid_plural "minutes"
|
||||
msgstr[0] "minutt"
|
||||
msgstr[1] "minutter"
|
||||
|
||||
#: ../js/ui/status/power.js:125
|
||||
#: ../js/ui/status/power.js:124
|
||||
#, c-format
|
||||
msgid "%d minute remaining"
|
||||
msgid_plural "%d minutes remaining"
|
||||
msgstr[0] "%d minutt gjenstår"
|
||||
msgstr[1] "%d minutter gjenstår"
|
||||
|
||||
#: ../js/ui/status/power.js:227
|
||||
#: ../js/ui/status/power.js:216
|
||||
msgid "AC adapter"
|
||||
msgstr "Strømadapter"
|
||||
|
||||
#: ../js/ui/status/power.js:229
|
||||
#: ../js/ui/status/power.js:218
|
||||
msgid "Laptop battery"
|
||||
msgstr "Batteri på bærbar"
|
||||
|
||||
#: ../js/ui/status/power.js:231
|
||||
#: ../js/ui/status/power.js:220
|
||||
msgid "UPS"
|
||||
msgstr "UPS"
|
||||
|
||||
#: ../js/ui/status/power.js:233
|
||||
#: ../js/ui/status/power.js:222
|
||||
msgid "Monitor"
|
||||
msgstr "Skjerm"
|
||||
|
||||
#: ../js/ui/status/power.js:235
|
||||
#: ../js/ui/status/power.js:224
|
||||
msgid "Mouse"
|
||||
msgstr "Mus"
|
||||
|
||||
#: ../js/ui/status/power.js:237
|
||||
#: ../js/ui/status/power.js:226
|
||||
msgid "Keyboard"
|
||||
msgstr "Tastatur"
|
||||
|
||||
#: ../js/ui/status/power.js:239
|
||||
#: ../js/ui/status/power.js:228
|
||||
msgid "PDA"
|
||||
msgstr "PDA"
|
||||
|
||||
#: ../js/ui/status/power.js:241
|
||||
#: ../js/ui/status/power.js:230
|
||||
msgid "Cell phone"
|
||||
msgstr "Mobiltelefon"
|
||||
|
||||
#: ../js/ui/status/power.js:243
|
||||
#: ../js/ui/status/power.js:232
|
||||
msgid "Media player"
|
||||
msgstr "Medieavspiller"
|
||||
|
||||
#: ../js/ui/status/power.js:245
|
||||
#: ../js/ui/status/power.js:234
|
||||
msgid "Tablet"
|
||||
msgstr "Nettbrett"
|
||||
|
||||
#: ../js/ui/status/power.js:247
|
||||
#: ../js/ui/status/power.js:236
|
||||
msgid "Computer"
|
||||
msgstr "Datamaskin"
|
||||
|
||||
#: ../js/ui/status/power.js:249 ../src/shell-app-system.c:1088
|
||||
#: ../js/ui/status/power.js:238 ../src/shell-app-system.c:1088
|
||||
msgid "Unknown"
|
||||
msgstr "Ukjent"
|
||||
|
||||
@ -1089,22 +1089,34 @@ msgstr "Volum"
|
||||
msgid "Microphone"
|
||||
msgstr "Mikrofon"
|
||||
|
||||
#: ../js/ui/telepathyClient.js:401
|
||||
#. We got the TpContact
|
||||
#. FIXME: We don't have a 'chat room' icon (bgo #653737) use
|
||||
#. system-users for now as Empathy does.
|
||||
#: ../js/ui/telepathyClient.js:228
|
||||
msgid "Invitation"
|
||||
msgstr "Invitasjon"
|
||||
|
||||
#. We got the TpContact
|
||||
#: ../js/ui/telepathyClient.js:291
|
||||
msgid "Call"
|
||||
msgstr "Ring"
|
||||
|
||||
#: ../js/ui/telepathyClient.js:541
|
||||
#, c-format
|
||||
msgid "%s is online."
|
||||
msgstr "%s er tilkoblet."
|
||||
|
||||
#: ../js/ui/telepathyClient.js:406
|
||||
#: ../js/ui/telepathyClient.js:546
|
||||
#, c-format
|
||||
msgid "%s is offline."
|
||||
msgstr "%s er frakoblet."
|
||||
|
||||
#: ../js/ui/telepathyClient.js:409
|
||||
#: ../js/ui/telepathyClient.js:549
|
||||
#, c-format
|
||||
msgid "%s is away."
|
||||
msgstr "«%s» er borte."
|
||||
|
||||
#: ../js/ui/telepathyClient.js:412
|
||||
#: ../js/ui/telepathyClient.js:552
|
||||
#, c-format
|
||||
msgid "%s is busy."
|
||||
msgstr "%s er opptatt."
|
||||
@ -1112,18 +1124,57 @@ msgstr "%s er opptatt."
|
||||
#. 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:560
|
||||
#: ../js/ui/telepathyClient.js:741
|
||||
#, no-c-format
|
||||
msgid "Sent at %X on %A"
|
||||
msgstr "Sendt %X på %A"
|
||||
|
||||
#. Translators: this is the other person changing their old IM name to their new
|
||||
#. IM name.
|
||||
#: ../js/ui/telepathyClient.js:610
|
||||
#: ../js/ui/telepathyClient.js:791
|
||||
#, c-format
|
||||
msgid "%s is now known as %s"
|
||||
msgstr "%s er nå kjent som %s"
|
||||
|
||||
#. translators: argument is a room name like
|
||||
#. * room@jabber.org for example.
|
||||
#: ../js/ui/telepathyClient.js:898
|
||||
#, c-format
|
||||
msgid "Invitation to %s"
|
||||
msgstr "Invitasjon til %s"
|
||||
|
||||
#. 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.
|
||||
#: ../js/ui/telepathyClient.js:906
|
||||
#, c-format
|
||||
msgid "%s is inviting you to join %s"
|
||||
msgstr "%s inviterer deg til å bli med i %s"
|
||||
|
||||
#: ../js/ui/telepathyClient.js:908
|
||||
msgid "Decline"
|
||||
msgstr "Avslå"
|
||||
|
||||
#: ../js/ui/telepathyClient.js:909
|
||||
msgid "Accept"
|
||||
msgstr "Godta"
|
||||
|
||||
#. translators: argument is a contact name like Alice for example.
|
||||
#: ../js/ui/telepathyClient.js:942
|
||||
#, c-format
|
||||
msgid "Video call from %s"
|
||||
msgstr "Videosamtale fra %s"
|
||||
|
||||
#. translators: argument is a contact name like Alice for example.
|
||||
#: ../js/ui/telepathyClient.js:945
|
||||
#, c-format
|
||||
msgid "Call from %s"
|
||||
msgstr "Samtale fra %s"
|
||||
|
||||
#: ../js/ui/telepathyClient.js:955
|
||||
msgid "Answer"
|
||||
msgstr "Svar"
|
||||
|
||||
#. Translators: this is the text displayed
|
||||
#. in the search entry when no search is
|
||||
#. active; it should not exceed ~30
|
||||
@ -1132,7 +1183,7 @@ msgstr "%s er nå kjent som %s"
|
||||
msgid "Type to search..."
|
||||
msgstr "Skriv for å søke …"
|
||||
|
||||
#: ../js/ui/viewSelector.js:140 ../src/shell-util.c:254
|
||||
#: ../js/ui/viewSelector.js:140 ../src/shell-util.c:257
|
||||
msgid "Search"
|
||||
msgstr "Søk"
|
||||
|
||||
@ -1168,7 +1219,7 @@ msgstr[1] "%u innganger"
|
||||
msgid "System Sounds"
|
||||
msgstr "Systemlyder"
|
||||
|
||||
#: ../src/main.c:445
|
||||
#: ../src/main.c:466
|
||||
msgid "Print version"
|
||||
msgstr "Skriv ut versjon"
|
||||
|
||||
@ -1189,13 +1240,13 @@ msgstr "Forvalg"
|
||||
msgid "Authentication dialog was dismissed by the user"
|
||||
msgstr "Autentiseringsdialogen ble lukket av brukeren"
|
||||
|
||||
#: ../src/shell-util.c:93
|
||||
#: ../src/shell-util.c:96
|
||||
msgid "Home Folder"
|
||||
msgstr "Hjemmemappe"
|
||||
|
||||
#. Translators: this is the same string as the one found in
|
||||
#. * nautilus
|
||||
#: ../src/shell-util.c:108
|
||||
#: ../src/shell-util.c:111
|
||||
msgid "File System"
|
||||
msgstr "Filsystem"
|
||||
|
||||
@ -1204,7 +1255,7 @@ msgstr "Filsystem"
|
||||
#. * example, "Trash: some-directory". It means that the
|
||||
#. * directory called "some-directory" is in the trash.
|
||||
#.
|
||||
#: ../src/shell-util.c:304
|
||||
#: ../src/shell-util.c:307
|
||||
#, c-format
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s: %2$s"
|
||||
|
208
po/sl.po
208
po/sl.po
@ -8,8 +8,8 @@ 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"
|
||||
"POT-Creation-Date: 2011-06-28 19:42+0000\n"
|
||||
"PO-Revision-Date: 2011-06-28 22:20+0100\n"
|
||||
"POT-Creation-Date: 2011-07-18 11:50+0000\n"
|
||||
"PO-Revision-Date: 2011-07-19 21:45+0100\n"
|
||||
"Last-Translator: Matej Urbančič <mateju@svn.gnome.org>\n"
|
||||
"Language-Team: Slovenian GNOME Translation Team <gnome-si@googlegroups.com>\n"
|
||||
"Language: Slovenian\n"
|
||||
@ -146,27 +146,27 @@ msgid "Execution of '%s' failed:"
|
||||
msgstr "Izvedba '%s' je spodletela:"
|
||||
|
||||
#. Translators: Filter to display all applications
|
||||
#: ../js/ui/appDisplay.js:258
|
||||
#: ../js/ui/appDisplay.js:252
|
||||
msgid "All"
|
||||
msgstr "Vse"
|
||||
|
||||
#: ../js/ui/appDisplay.js:357
|
||||
#: ../js/ui/appDisplay.js:359
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "Programi"
|
||||
|
||||
#: ../js/ui/appDisplay.js:383
|
||||
#: ../js/ui/appDisplay.js:385
|
||||
msgid "SETTINGS"
|
||||
msgstr "NASTAVITVE"
|
||||
|
||||
#: ../js/ui/appDisplay.js:656
|
||||
#: ../js/ui/appDisplay.js:658
|
||||
msgid "New Window"
|
||||
msgstr "Novo okno"
|
||||
|
||||
#: ../js/ui/appDisplay.js:659
|
||||
#: ../js/ui/appDisplay.js:661
|
||||
msgid "Remove from Favorites"
|
||||
msgstr "Odstrani iz priljubljenih"
|
||||
|
||||
#: ../js/ui/appDisplay.js:660
|
||||
#: ../js/ui/appDisplay.js:662
|
||||
msgid "Add to Favorites"
|
||||
msgstr "Dodaj med priljubljene"
|
||||
|
||||
@ -300,14 +300,14 @@ msgstr "Nič ni razporejeno"
|
||||
|
||||
#. Translators: Shown on calendar heading when selected day occurs on current year
|
||||
#: ../js/ui/calendar.js:717
|
||||
#: ../js/ui/telepathyClient.js:568
|
||||
#: ../js/ui/telepathyClient.js:749
|
||||
msgctxt "calendar heading"
|
||||
msgid "%A, %B %d"
|
||||
msgstr "%A, %d. %m."
|
||||
|
||||
#. Translators: Shown on calendar heading when selected day occurs on different year
|
||||
#: ../js/ui/calendar.js:720
|
||||
#: ../js/ui/telepathyClient.js:571
|
||||
#: ../js/ui/telepathyClient.js:752
|
||||
msgctxt "calendar heading"
|
||||
msgid "%A, %B %d, %Y"
|
||||
msgstr "%A, %d %B %Y"
|
||||
@ -329,7 +329,7 @@ msgid "Next week"
|
||||
msgstr "Naslednji teden"
|
||||
|
||||
#: ../js/ui/dash.js:172
|
||||
#: ../js/ui/messageTray.js:1044
|
||||
#: ../js/ui/messageTray.js:1122
|
||||
msgid "Remove"
|
||||
msgstr "Odstrani"
|
||||
|
||||
@ -494,11 +494,11 @@ msgstr "Poglej vir"
|
||||
msgid "Web Page"
|
||||
msgstr "Spletna stran"
|
||||
|
||||
#: ../js/ui/messageTray.js:1037
|
||||
#: ../js/ui/messageTray.js:1115
|
||||
msgid "Open"
|
||||
msgstr "Odpri"
|
||||
|
||||
#: ../js/ui/messageTray.js:2207
|
||||
#: ../js/ui/messageTray.js:2286
|
||||
msgid "System Information"
|
||||
msgstr "Podrobnosti sistema"
|
||||
|
||||
@ -521,18 +521,18 @@ msgid "Dash"
|
||||
msgstr "Armaturna plošča"
|
||||
|
||||
#. TODO - _quit() doesn't really work on apps in state STARTING yet
|
||||
#: ../js/ui/panel.js:533
|
||||
#: ../js/ui/panel.js:532
|
||||
#, c-format
|
||||
msgid "Quit %s"
|
||||
msgstr "Končaj %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
|
||||
#. Translators: If there is no suitable word for "Activities"
|
||||
#. in your language, you can use the word for "Overview".
|
||||
#: ../js/ui/panel.js:568
|
||||
msgid "Activities"
|
||||
msgstr "Dejavnosti"
|
||||
|
||||
#: ../js/ui/panel.js:1013
|
||||
#: ../js/ui/panel.js:951
|
||||
msgid "Top Bar"
|
||||
msgstr "Vrhnja vrstica"
|
||||
|
||||
@ -598,43 +598,43 @@ msgstr "Iskanje ..."
|
||||
msgid "No matching results."
|
||||
msgstr "Ni zadetkov iskanja"
|
||||
|
||||
#: ../js/ui/statusMenu.js:202
|
||||
#: ../js/ui/statusMenu.js:206
|
||||
#: ../js/ui/statusMenu.js:272
|
||||
#: ../js/ui/statusMenu.js:192
|
||||
#: ../js/ui/statusMenu.js:196
|
||||
#: ../js/ui/statusMenu.js:262
|
||||
msgid "Power Off..."
|
||||
msgstr "Izklop ..."
|
||||
|
||||
#: ../js/ui/statusMenu.js:204
|
||||
#: ../js/ui/statusMenu.js:206
|
||||
#: ../js/ui/statusMenu.js:271
|
||||
#: ../js/ui/statusMenu.js:194
|
||||
#: ../js/ui/statusMenu.js:196
|
||||
#: ../js/ui/statusMenu.js:261
|
||||
msgid "Suspend"
|
||||
msgstr "Zaustavi"
|
||||
|
||||
#: ../js/ui/statusMenu.js:227
|
||||
#: ../js/ui/statusMenu.js:217
|
||||
msgid "Available"
|
||||
msgstr "Na voljo"
|
||||
|
||||
#: ../js/ui/statusMenu.js:232
|
||||
#: ../js/ui/statusMenu.js:222
|
||||
msgid "Busy"
|
||||
msgstr "Zaposleno"
|
||||
|
||||
#: ../js/ui/statusMenu.js:240
|
||||
#: ../js/ui/statusMenu.js:230
|
||||
msgid "My Account"
|
||||
msgstr "Račun"
|
||||
|
||||
#: ../js/ui/statusMenu.js:244
|
||||
#: ../js/ui/statusMenu.js:234
|
||||
msgid "System Settings"
|
||||
msgstr "Sistemske nastavitve"
|
||||
|
||||
#: ../js/ui/statusMenu.js:252
|
||||
#: ../js/ui/statusMenu.js:242
|
||||
msgid "Lock Screen"
|
||||
msgstr "Zakleni zaslon"
|
||||
|
||||
#: ../js/ui/statusMenu.js:257
|
||||
#: ../js/ui/statusMenu.js:247
|
||||
msgid "Switch User"
|
||||
msgstr "Preklopi uporabnika"
|
||||
|
||||
#: ../js/ui/statusMenu.js:262
|
||||
#: ../js/ui/statusMenu.js:252
|
||||
msgid "Log Out..."
|
||||
msgstr "Odjava ..."
|
||||
|
||||
@ -773,6 +773,7 @@ msgid "Grant this time only"
|
||||
msgstr "Odobri le tokrat"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:409
|
||||
#: ../js/ui/telepathyClient.js:954
|
||||
msgid "Reject"
|
||||
msgstr "Zavrni"
|
||||
|
||||
@ -863,14 +864,14 @@ msgid "connection failed"
|
||||
msgstr "povezovanje je spodletelo"
|
||||
|
||||
#: ../js/ui/status/network.js:582
|
||||
#: ../js/ui/status/network.js:1489
|
||||
#: ../js/ui/status/network.js:1507
|
||||
msgid "More..."
|
||||
msgstr "Več ..."
|
||||
|
||||
#. 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:618
|
||||
#: ../js/ui/status/network.js:1427
|
||||
#: ../js/ui/status/network.js:1444
|
||||
msgid "Connected (private)"
|
||||
msgstr "Povezano (zasebna povezava)"
|
||||
|
||||
@ -888,7 +889,7 @@ msgstr "Samodejni klicni dostop"
|
||||
|
||||
#. TRANSLATORS: this the automatic wireless connection name (including the network name)
|
||||
#: ../js/ui/status/network.js:898
|
||||
#: ../js/ui/status/network.js:1439
|
||||
#: ../js/ui/status/network.js:1456
|
||||
#, c-format
|
||||
msgid "Auto %s"
|
||||
msgstr "Samodejna povezava z %s"
|
||||
@ -897,68 +898,68 @@ msgstr "Samodejna povezava z %s"
|
||||
msgid "Auto bluetooth"
|
||||
msgstr "Samodejna povezava z Bluetooth"
|
||||
|
||||
#: ../js/ui/status/network.js:1441
|
||||
#: ../js/ui/status/network.js:1458
|
||||
msgid "Auto wireless"
|
||||
msgstr "Samodejni brezžični dostop"
|
||||
|
||||
#: ../js/ui/status/network.js:1531
|
||||
#: ../js/ui/status/network.js:1550
|
||||
msgid "Enable networking"
|
||||
msgstr "Omogoči omrežje"
|
||||
|
||||
#: ../js/ui/status/network.js:1543
|
||||
#: ../js/ui/status/network.js:1562
|
||||
msgid "Wired"
|
||||
msgstr "Žično"
|
||||
|
||||
#: ../js/ui/status/network.js:1554
|
||||
#: ../js/ui/status/network.js:1573
|
||||
msgid "Wireless"
|
||||
msgstr "Brezžično"
|
||||
|
||||
#: ../js/ui/status/network.js:1564
|
||||
#: ../js/ui/status/network.js:1583
|
||||
msgid "Mobile broadband"
|
||||
msgstr "Mobilni širokopasovni dostop"
|
||||
|
||||
#: ../js/ui/status/network.js:1574
|
||||
#: ../js/ui/status/network.js:1593
|
||||
msgid "VPN Connections"
|
||||
msgstr "Povezave VPN"
|
||||
|
||||
#: ../js/ui/status/network.js:1586
|
||||
#: ../js/ui/status/network.js:1605
|
||||
msgid "Network Settings"
|
||||
msgstr "Omrežne nastavitve"
|
||||
|
||||
#: ../js/ui/status/network.js:1878
|
||||
#: ../js/ui/status/network.js:1897
|
||||
#, c-format
|
||||
msgid "You're now connected to mobile broadband connection '%s'"
|
||||
msgstr "Vzpostavljena je povezava z mobilnim širokopasovnim omrežjem '%s'."
|
||||
|
||||
#: ../js/ui/status/network.js:1882
|
||||
#: ../js/ui/status/network.js:1901
|
||||
#, c-format
|
||||
msgid "You're now connected to wireless network '%s'"
|
||||
msgstr "Vzpostavljena je povezava z brezžičnim omrežjem '%s'."
|
||||
|
||||
#: ../js/ui/status/network.js:1886
|
||||
#: ../js/ui/status/network.js:1905
|
||||
#, c-format
|
||||
msgid "You're now connected to wired network '%s'"
|
||||
msgstr "Vzpostavljena je povezava z žičnim omrežjem '%s'."
|
||||
|
||||
#: ../js/ui/status/network.js:1890
|
||||
#: ../js/ui/status/network.js:1909
|
||||
#, c-format
|
||||
msgid "You're now connected to VPN network '%s'"
|
||||
msgstr "Vzpostavljena je povezava z omrežjem VPN '%s'"
|
||||
|
||||
#: ../js/ui/status/network.js:1895
|
||||
#: ../js/ui/status/network.js:1914
|
||||
#, c-format
|
||||
msgid "You're now connected to '%s'"
|
||||
msgstr "Vzpostavljena je povezava z '%s'."
|
||||
|
||||
#: ../js/ui/status/network.js:1903
|
||||
#: ../js/ui/status/network.js:1922
|
||||
msgid "Connection established"
|
||||
msgstr "Povezava je vzpostavljena"
|
||||
|
||||
#: ../js/ui/status/network.js:2029
|
||||
#: ../js/ui/status/network.js:2048
|
||||
msgid "Networking is disabled"
|
||||
msgstr "Omrežje je onemogočeno"
|
||||
|
||||
#: ../js/ui/status/network.js:2154
|
||||
#: ../js/ui/status/network.js:2173
|
||||
msgid "Network Manager"
|
||||
msgstr "Upravljalnik omrežij"
|
||||
|
||||
@ -968,11 +969,11 @@ msgstr "Upravljanje napajanja"
|
||||
|
||||
#. 0 is reported when UPower does not have enough data
|
||||
#. to estimate battery life
|
||||
#: ../js/ui/status/power.js:110
|
||||
#: ../js/ui/status/power.js:109
|
||||
msgid "Estimating..."
|
||||
msgstr "Ocenjevanje ...."
|
||||
|
||||
#: ../js/ui/status/power.js:117
|
||||
#: ../js/ui/status/power.js:116
|
||||
#, c-format
|
||||
msgid "%d hour remaining"
|
||||
msgid_plural "%d hours remaining"
|
||||
@ -982,12 +983,12 @@ msgstr[2] "preostajata še %d uri"
|
||||
msgstr[3] "preostajajo še %d ure"
|
||||
|
||||
#. TRANSLATORS: this is a time string, as in "%d hours %d minutes remaining"
|
||||
#: ../js/ui/status/power.js:120
|
||||
#: ../js/ui/status/power.js:119
|
||||
#, c-format
|
||||
msgid "%d %s %d %s remaining"
|
||||
msgstr "Preostaja še %d %s %d %s"
|
||||
|
||||
#: ../js/ui/status/power.js:122
|
||||
#: ../js/ui/status/power.js:121
|
||||
msgid "hour"
|
||||
msgid_plural "hours"
|
||||
msgstr[0] "ur"
|
||||
@ -995,7 +996,7 @@ msgstr[1] "ura"
|
||||
msgstr[2] "uri"
|
||||
msgstr[3] "ure"
|
||||
|
||||
#: ../js/ui/status/power.js:122
|
||||
#: ../js/ui/status/power.js:121
|
||||
msgid "minute"
|
||||
msgid_plural "minutes"
|
||||
msgstr[0] "minut"
|
||||
@ -1003,7 +1004,7 @@ msgstr[1] "minuta"
|
||||
msgstr[2] "minuti"
|
||||
msgstr[3] "minute"
|
||||
|
||||
#: ../js/ui/status/power.js:125
|
||||
#: ../js/ui/status/power.js:124
|
||||
#, c-format
|
||||
msgid "%d minute remaining"
|
||||
msgid_plural "%d minutes remaining"
|
||||
@ -1012,51 +1013,51 @@ msgstr[1] "preostaja še %d minuta"
|
||||
msgstr[2] "preostajata še %d minuti"
|
||||
msgstr[3] "preostajajo še %d minute"
|
||||
|
||||
#: ../js/ui/status/power.js:227
|
||||
#: ../js/ui/status/power.js:216
|
||||
msgid "AC adapter"
|
||||
msgstr "Električni prilagodilnik"
|
||||
|
||||
#: ../js/ui/status/power.js:229
|
||||
#: ../js/ui/status/power.js:218
|
||||
msgid "Laptop battery"
|
||||
msgstr "Baterija prenosnika"
|
||||
|
||||
#: ../js/ui/status/power.js:231
|
||||
#: ../js/ui/status/power.js:220
|
||||
msgid "UPS"
|
||||
msgstr "UPS"
|
||||
|
||||
#: ../js/ui/status/power.js:233
|
||||
#: ../js/ui/status/power.js:222
|
||||
msgid "Monitor"
|
||||
msgstr "Zaslon"
|
||||
|
||||
#: ../js/ui/status/power.js:235
|
||||
#: ../js/ui/status/power.js:224
|
||||
msgid "Mouse"
|
||||
msgstr "Miška"
|
||||
|
||||
#: ../js/ui/status/power.js:237
|
||||
#: ../js/ui/status/power.js:226
|
||||
msgid "Keyboard"
|
||||
msgstr "Tipkovnica"
|
||||
|
||||
#: ../js/ui/status/power.js:239
|
||||
#: ../js/ui/status/power.js:228
|
||||
msgid "PDA"
|
||||
msgstr "Dlančnik"
|
||||
|
||||
#: ../js/ui/status/power.js:241
|
||||
#: ../js/ui/status/power.js:230
|
||||
msgid "Cell phone"
|
||||
msgstr "Mobilni telefon"
|
||||
|
||||
#: ../js/ui/status/power.js:243
|
||||
#: ../js/ui/status/power.js:232
|
||||
msgid "Media player"
|
||||
msgstr "Predstavni predvajalnik"
|
||||
|
||||
#: ../js/ui/status/power.js:245
|
||||
#: ../js/ui/status/power.js:234
|
||||
msgid "Tablet"
|
||||
msgstr "Tablični računalnik"
|
||||
|
||||
#: ../js/ui/status/power.js:247
|
||||
#: ../js/ui/status/power.js:236
|
||||
msgid "Computer"
|
||||
msgstr "Računalnik"
|
||||
|
||||
#: ../js/ui/status/power.js:249
|
||||
#: ../js/ui/status/power.js:238
|
||||
#: ../src/shell-app-system.c:1088
|
||||
msgid "Unknown"
|
||||
msgstr "Neznano"
|
||||
@ -1069,22 +1070,34 @@ msgstr "Glasnost"
|
||||
msgid "Microphone"
|
||||
msgstr "Mikrofon"
|
||||
|
||||
#: ../js/ui/telepathyClient.js:401
|
||||
#. We got the TpContact
|
||||
#. FIXME: We don't have a 'chat room' icon (bgo #653737) use
|
||||
#. system-users for now as Empathy does.
|
||||
#: ../js/ui/telepathyClient.js:228
|
||||
msgid "Invitation"
|
||||
msgstr "Povabilo"
|
||||
|
||||
#. We got the TpContact
|
||||
#: ../js/ui/telepathyClient.js:291
|
||||
msgid "Call"
|
||||
msgstr "Pokliči"
|
||||
|
||||
#: ../js/ui/telepathyClient.js:541
|
||||
#, c-format
|
||||
msgid "%s is online."
|
||||
msgstr "%s je povezan."
|
||||
|
||||
#: ../js/ui/telepathyClient.js:406
|
||||
#: ../js/ui/telepathyClient.js:546
|
||||
#, c-format
|
||||
msgid "%s is offline."
|
||||
msgstr "%s ni povezan."
|
||||
|
||||
#: ../js/ui/telepathyClient.js:409
|
||||
#: ../js/ui/telepathyClient.js:549
|
||||
#, c-format
|
||||
msgid "%s is away."
|
||||
msgstr "%s je odsoten."
|
||||
|
||||
#: ../js/ui/telepathyClient.js:412
|
||||
#: ../js/ui/telepathyClient.js:552
|
||||
#, c-format
|
||||
msgid "%s is busy."
|
||||
msgstr "%s je zaposlen."
|
||||
@ -1092,18 +1105,57 @@ msgstr "%s je zaposlen."
|
||||
#. 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:560
|
||||
#: ../js/ui/telepathyClient.js:741
|
||||
#, no-c-format
|
||||
msgid "Sent at %X on %A"
|
||||
msgstr "Poslano na %X ob %A"
|
||||
|
||||
#. Translators: this is the other person changing their old IM name to their new
|
||||
#. IM name.
|
||||
#: ../js/ui/telepathyClient.js:610
|
||||
#: ../js/ui/telepathyClient.js:791
|
||||
#, c-format
|
||||
msgid "%s is now known as %s"
|
||||
msgstr "%s je sedaj znan kot v %s"
|
||||
|
||||
#. translators: argument is a room name like
|
||||
#. * room@jabber.org for example.
|
||||
#: ../js/ui/telepathyClient.js:898
|
||||
#, c-format
|
||||
msgid "Invitation to %s"
|
||||
msgstr "Povabilo v %s"
|
||||
|
||||
#. 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.
|
||||
#: ../js/ui/telepathyClient.js:906
|
||||
#, c-format
|
||||
msgid "%s is inviting you to join %s"
|
||||
msgstr "%s vas vabi, da se pridružite v %s"
|
||||
|
||||
#: ../js/ui/telepathyClient.js:908
|
||||
msgid "Decline"
|
||||
msgstr "Zavrni"
|
||||
|
||||
#: ../js/ui/telepathyClient.js:909
|
||||
msgid "Accept"
|
||||
msgstr "Sprejmi"
|
||||
|
||||
#. translators: argument is a contact name like Alice for example.
|
||||
#: ../js/ui/telepathyClient.js:942
|
||||
#, c-format
|
||||
msgid "Video call from %s"
|
||||
msgstr "%s želi vzpostaviti video klic"
|
||||
|
||||
#. translators: argument is a contact name like Alice for example.
|
||||
#: ../js/ui/telepathyClient.js:945
|
||||
#, c-format
|
||||
msgid "Call from %s"
|
||||
msgstr "%s kliče"
|
||||
|
||||
#: ../js/ui/telepathyClient.js:955
|
||||
msgid "Answer"
|
||||
msgstr "Odgovori"
|
||||
|
||||
#. Translators: this is the text displayed
|
||||
#. in the search entry when no search is
|
||||
#. active; it should not exceed ~30
|
||||
@ -1113,7 +1165,7 @@ msgid "Type to search..."
|
||||
msgstr "Vtipkajte za iskanje ..."
|
||||
|
||||
#: ../js/ui/viewSelector.js:140
|
||||
#: ../src/shell-util.c:254
|
||||
#: ../src/shell-util.c:257
|
||||
msgid "Search"
|
||||
msgstr "Poišči"
|
||||
|
||||
@ -1153,7 +1205,7 @@ msgstr[3] "%u dovodi naprave"
|
||||
msgid "System Sounds"
|
||||
msgstr "Sistemski zvoki"
|
||||
|
||||
#: ../src/main.c:445
|
||||
#: ../src/main.c:466
|
||||
msgid "Print version"
|
||||
msgstr "Izpiši različico"
|
||||
|
||||
@ -1174,13 +1226,13 @@ msgstr "Privzeto"
|
||||
msgid "Authentication dialog was dismissed by the user"
|
||||
msgstr "Uporabnik je zavrnil pogovorno okno overitve"
|
||||
|
||||
#: ../src/shell-util.c:93
|
||||
#: ../src/shell-util.c:96
|
||||
msgid "Home Folder"
|
||||
msgstr "Domača mapa"
|
||||
|
||||
#. Translators: this is the same string as the one found in
|
||||
#. * nautilus
|
||||
#: ../src/shell-util.c:108
|
||||
#: ../src/shell-util.c:111
|
||||
msgid "File System"
|
||||
msgstr "Datotečni sistem"
|
||||
|
||||
@ -1189,7 +1241,7 @@ msgstr "Datotečni sistem"
|
||||
#. * example, "Trash: some-directory". It means that the
|
||||
#. * directory called "some-directory" is in the trash.
|
||||
#.
|
||||
#: ../src/shell-util.c:304
|
||||
#: ../src/shell-util.c:307
|
||||
#, c-format
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s: %2$s"
|
||||
|
@ -1,13 +1,4 @@
|
||||
|
||||
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)
|
||||
service_in_files += calendar-server/org.gnome.Shell.CalendarServer.service.in
|
||||
|
||||
libexec_PROGRAMS += gnome-shell-calendar-server
|
||||
|
||||
|
24
src/Makefile-hotplug-sniffer.am
Normal file
24
src/Makefile-hotplug-sniffer.am
Normal file
@ -0,0 +1,24 @@
|
||||
service_in_files += hotplug-sniffer/org.gnome.Shell.HotplugSniffer.service.in
|
||||
|
||||
libexec_PROGRAMS += gnome-shell-hotplug-sniffer
|
||||
|
||||
gnome_shell_hotplug_sniffer_SOURCES = \
|
||||
hotplug-sniffer/hotplug-mimetypes.h \
|
||||
hotplug-sniffer/shell-mime-sniffer.h \
|
||||
hotplug-sniffer/shell-mime-sniffer.c \
|
||||
hotplug-sniffer/hotplug-sniffer.c \
|
||||
$(NULL)
|
||||
|
||||
gnome_shell_hotplug_sniffer_CFLAGS = \
|
||||
-I$(top_srcdir)/src \
|
||||
-DG_DISABLE_DEPRECATED \
|
||||
$(SHELL_HOTPLUG_SNIFFER_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
gnome_shell_hotplug_sniffer_LDFLAGS = \
|
||||
$(SHELL_HOTPLUG_SNIFFER_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST += \
|
||||
hotplug-sniffer/org.gnome.Shell.HotplugSniffer.service.in \
|
||||
$(NULL)
|
@ -6,6 +6,7 @@ bin_SCRIPTS =
|
||||
libexec_PROGRAMS =
|
||||
noinst_LTLIBRARIES =
|
||||
noinst_PROGRAMS =
|
||||
service_in_files =
|
||||
|
||||
-include $(INTROSPECTION_MAKEFILE)
|
||||
INTROSPECTION_GIRS =
|
||||
@ -15,9 +16,19 @@ INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir) --includedir=$(MUTTER_TYPEL
|
||||
typelibdir = $(pkglibdir)
|
||||
typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
|
||||
|
||||
servicedir = $(datadir)/dbus-1/services
|
||||
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)
|
||||
|
||||
CLEANFILES += $(gir_DATA) $(typelib_DATA)
|
||||
|
||||
bin_SCRIPTS += gnome-shell-extension-tool
|
||||
EXTRA_DIST += gnome-shell-extension-tool.in
|
||||
bin_PROGRAMS = gnome-shell-real
|
||||
|
||||
if USE_JHBUILD_WRAPPER_SCRIPT
|
||||
@ -26,6 +37,7 @@ bin_SCRIPTS += gnome-shell-jhbuild
|
||||
else
|
||||
gnome_shell = gnome-shell-real
|
||||
endif
|
||||
EXTRA_DIST += gnome-shell-jhbuild.in
|
||||
|
||||
noinst_DATA = gnome-shell
|
||||
gnome-shell: $(gnome_shell) Makefile
|
||||
@ -55,13 +67,13 @@ gnome-shell-extension-tool: gnome-shell-extension-tool.in Makefile
|
||||
$(AM_V_GEN) sed $(generated_script_substitutions) $< > $@.tmp && mv $@.tmp $@ && chmod a+x $@
|
||||
|
||||
CLEANFILES += gnome-shell $(bin_SCRIPTS)
|
||||
EXTRA_DIST += $(bin_SCRIPTS:=.in)
|
||||
|
||||
include Makefile-gdmuser.am
|
||||
include Makefile-st.am
|
||||
include Makefile-tray.am
|
||||
include Makefile-gvc.am
|
||||
include Makefile-calendar-server.am
|
||||
include Makefile-hotplug-sniffer.am
|
||||
|
||||
gnome_shell_cflags = \
|
||||
$(GNOME_SHELL_CFLAGS) \
|
||||
@ -97,6 +109,7 @@ shell_public_headers_h = \
|
||||
shell-gtk-embed.h \
|
||||
shell-global.h \
|
||||
shell-mobile-providers.h \
|
||||
shell-mount-operation.h \
|
||||
shell-perf-log.h \
|
||||
shell-slicer.h \
|
||||
shell-stack.h \
|
||||
@ -130,6 +143,7 @@ libgnome_shell_la_SOURCES = \
|
||||
shell-gtk-embed.c \
|
||||
shell-global.c \
|
||||
shell-mobile-providers.c \
|
||||
shell-mount-operation.c \
|
||||
shell-perf-log.c \
|
||||
shell-polkit-authentication-agent.h \
|
||||
shell-polkit-authentication-agent.c \
|
||||
@ -255,7 +269,7 @@ libgnome_shell_la_LIBADD = \
|
||||
libgnome_shell_la_CPPFLAGS = $(gnome_shell_cflags)
|
||||
|
||||
Shell-0.1.gir: libgnome-shell.la St-1.0.gir
|
||||
Shell_0_1_gir_INCLUDES = Clutter-1.0 ClutterX11-1.0 Meta-3.0 TelepathyGLib-0.12 TelepathyLogger-0.2
|
||||
Shell_0_1_gir_INCLUDES = Clutter-1.0 ClutterX11-1.0 Meta-3.0 TelepathyGLib-0.12 TelepathyLogger-0.2 Soup-2.4
|
||||
Shell_0_1_gir_CFLAGS = $(libgnome_shell_la_CPPFLAGS) -I $(srcdir)
|
||||
Shell_0_1_gir_LIBS = libgnome-shell.la
|
||||
Shell_0_1_gir_FILES = $(libgnome_shell_la_gir_sources)
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
import os
|
||||
import re
|
||||
import socket
|
||||
import subprocess
|
||||
import sys
|
||||
import optparse
|
||||
@ -26,6 +27,69 @@ if args:
|
||||
parser.print_usage()
|
||||
sys.exit(1)
|
||||
|
||||
SAMPLE_EXTENSION_FILES = {
|
||||
"extension.js": """
|
||||
const St = imports.gi.St;
|
||||
const Main = imports.ui.main;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
let text;
|
||||
|
||||
function _hideHello() {
|
||||
Main.uiGroup.remove_actor(text);
|
||||
text = null;
|
||||
}
|
||||
|
||||
function _showHello() {
|
||||
if (!text) {
|
||||
text = new St.Label({ style_class: 'helloworld-label', text: "Hello, world!" });
|
||||
Main.uiGroup.add_actor(text);
|
||||
}
|
||||
|
||||
text.opacity = 255;
|
||||
|
||||
let monitor = Main.layoutManager.primaryMonitor;
|
||||
|
||||
text.set_position(Math.floor(monitor.width / 2 - text.width / 2),
|
||||
Math.floor(monitor.height / 2 - text.height / 2));
|
||||
|
||||
Tweener.addTween(text,
|
||||
{ opacity: 0,
|
||||
time: 2,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: _hideHello });
|
||||
}
|
||||
|
||||
function main() {
|
||||
let button = new St.Bin({ style_class: 'panel-button',
|
||||
reactive: true,
|
||||
can_focus: true,
|
||||
x_fill: true,
|
||||
y_fill: false,
|
||||
track_hover: true });
|
||||
let icon = new St.Icon({ icon_name: 'system-run',
|
||||
icon_type: St.IconType.SYMBOLIC,
|
||||
style_class: 'system-status-icon' });
|
||||
|
||||
button.set_child(icon);
|
||||
button.connect('button-press-event', _showHello);
|
||||
|
||||
Main.panel._rightBox.insert_actor(button, 0);
|
||||
}
|
||||
""",
|
||||
|
||||
"stylesheet.css": """
|
||||
.helloworld-label {
|
||||
font-size: 36px;
|
||||
font-weight: bold;
|
||||
color: #ffffff;
|
||||
background-color: rgba(10,10,10,0.7);
|
||||
border-radius: 5px;
|
||||
padding: .5em;
|
||||
}
|
||||
""",
|
||||
}
|
||||
|
||||
if options.create_extension:
|
||||
print
|
||||
print '''Name should be a very short (ideally descriptive) string.
|
||||
@ -41,7 +105,7 @@ Examples are: "Make windows visible on click", "Block advertisement popups"
|
||||
underifier = re.compile('[^A-Za-z]')
|
||||
sample_uuid = underifier.sub('_', name)
|
||||
# TODO use evolution data server
|
||||
hostname = subprocess.Popen(['hostname'], stdout=subprocess.PIPE).communicate()[0].strip()
|
||||
hostname = socket.gethostname()
|
||||
sample_uuid = sample_uuid + '@' + hostname
|
||||
|
||||
print
|
||||
@ -71,41 +135,11 @@ use an extension title clicktofocus@janedoe.example.com.'''
|
||||
f.write(json.write(meta) + '\n')
|
||||
f.close()
|
||||
|
||||
extensionjs_path = os.path.join(extension_path, 'extension.js')
|
||||
f = open(extensionjs_path, 'w')
|
||||
f.write('''// Sample extension code, makes clicking on the panel show a message
|
||||
const St = imports.gi.St;
|
||||
const Mainloop = imports.mainloop;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
|
||||
function _showHello() {
|
||||
let text = new St.Label({ style_class: 'helloworld-label', text: "Hello, world!" });
|
||||
let monitor = global.get_primary_monitor();
|
||||
global.stage.add_actor(text);
|
||||
text.set_position(Math.floor (monitor.width / 2 - text.width / 2), Math.floor(monitor.height / 2 - text.height / 2));
|
||||
Mainloop.timeout_add(3000, function () { text.destroy(); });
|
||||
}
|
||||
|
||||
// Put your extension initialization code here
|
||||
function main() {
|
||||
Main.panel.actor.reactive = true;
|
||||
Main.panel.actor.connect('button-release-event', _showHello);
|
||||
}
|
||||
''')
|
||||
f.close()
|
||||
|
||||
f = open(os.path.join(extension_path, 'stylesheet.css'), 'w')
|
||||
f.write('''/* Example stylesheet */
|
||||
.helloworld-label {
|
||||
font-size: 36px;
|
||||
font-weight: bold;
|
||||
color: #ffffff;
|
||||
background-color: rgba(10,10,10,0.7);
|
||||
border-radius: 5px;
|
||||
}
|
||||
''')
|
||||
f.close()
|
||||
for filename, contents in SAMPLE_EXTENSION_FILES.iteritems():
|
||||
path = os.path.join(extension_path, filename)
|
||||
f = open(path, 'w')
|
||||
f.write(contents)
|
||||
f.close()
|
||||
|
||||
print "Created extension in %r" % (extension_path, )
|
||||
subprocess.Popen(['gnome-open', extensionjs_path])
|
||||
|
@ -532,7 +532,7 @@ def restore_gnome():
|
||||
component = client.get_string(gconf_path)
|
||||
|
||||
if component == None or component == "":
|
||||
return
|
||||
return False
|
||||
|
||||
# See gnome-session/gsm-util.c:gsm_util_find_desktop_file_for_app_name()
|
||||
# The one difference is that we don't search the autostart directories,
|
||||
@ -549,9 +549,15 @@ def restore_gnome():
|
||||
|
||||
if appinfo:
|
||||
appinfo.launch()
|
||||
return True
|
||||
return False
|
||||
|
||||
launch_component("/desktop/gnome/session/required_components/windowmanager")
|
||||
launch_component("/desktop/gnome/session/required_components/panel")
|
||||
# GNOME2 fallback
|
||||
wm = launch_component("/desktop/gnome/session/required_components/windowmanager")
|
||||
panel = launch_component("/desktop/gnome/session/required_components/panel")
|
||||
|
||||
if not wm and not panel: # Probably GNOME3
|
||||
subprocess.Popen(['gnome-shell'])
|
||||
|
||||
# Main program
|
||||
|
||||
|
139
src/hotplug-sniffer/hotplug-mimetypes.h
Normal file
139
src/hotplug-sniffer/hotplug-mimetypes.h
Normal file
@ -0,0 +1,139 @@
|
||||
#ifndef __HOTPLUG_MIMETYPES_H__
|
||||
#define __HOTPLUG_MIMETYPES_H__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
G_GNUC_UNUSED static const gchar *docs_mimetypes[] = {
|
||||
"application/vnd.oasis.opendocument.text",
|
||||
"application/vnd.oasis.opendocument.presentation",
|
||||
"application/vnd.oasis.opendocument.spreadsheet",
|
||||
"application/msword",
|
||||
"application/vnd.ms-excel",
|
||||
"application/vnd.ms-powerpoint",
|
||||
"application/rtf",
|
||||
"application/pdf",
|
||||
"application/x-bzpdf",
|
||||
"application/x-gzpdf",
|
||||
"application/x-xzpdf",
|
||||
"application/postscript",
|
||||
"application/x-bzpostscript",
|
||||
"application/x-gzpostscript",
|
||||
"image/x-eps",
|
||||
"image/x-bzeps",
|
||||
"image/x-gzeps",
|
||||
"application/x-dvi",
|
||||
"application/x-bzdvi",
|
||||
"application/x-gzdvi",
|
||||
"image/vnd.djvu",
|
||||
"application/x-cbr",
|
||||
"application/x-cbz",
|
||||
"application/x-cb7",
|
||||
"application/x-cbt",
|
||||
NULL
|
||||
};
|
||||
|
||||
G_GNUC_UNUSED static const gchar *video_mimetypes[] = {
|
||||
"application/mxf",
|
||||
"application/ogg",
|
||||
"application/ram",
|
||||
"application/sdp",
|
||||
"application/vnd.ms-wpl",
|
||||
"application/vnd.rn-realmedia",
|
||||
"application/x-extension-m4a",
|
||||
"application/x-extension-mp4",
|
||||
"application/x-flash-video",
|
||||
"application/x-matroska",
|
||||
"application/x-netshow-channel",
|
||||
"application/x-ogg",
|
||||
"application/x-quicktimeplayer",
|
||||
"application/x-shorten",
|
||||
"image/vnd.rn-realpix",
|
||||
"image/x-pict",
|
||||
"misc/ultravox",
|
||||
"text/x-google-video-pointer",
|
||||
"video/3gpp",
|
||||
"video/dv",
|
||||
"video/fli",
|
||||
"video/flv",
|
||||
"video/mp2t",
|
||||
"video/mp4",
|
||||
"video/mp4v-es",
|
||||
"video/mpeg",
|
||||
"video/msvideo",
|
||||
"video/ogg",
|
||||
"video/quicktime",
|
||||
"video/vivo",
|
||||
"video/vnd.divx",
|
||||
"video/vnd.rn-realvideo",
|
||||
"video/vnd.vivo",
|
||||
"video/webm",
|
||||
"video/x-anim",
|
||||
"video/x-avi",
|
||||
"video/x-flc",
|
||||
"video/x-fli",
|
||||
"video/x-flic",
|
||||
"video/x-flv",
|
||||
"video/x-m4v",
|
||||
"video/x-matroska",
|
||||
"video/x-mpeg",
|
||||
"video/x-ms-asf",
|
||||
"video/x-ms-asx",
|
||||
"video/x-msvideo",
|
||||
"video/x-ms-wm",
|
||||
"video/x-ms-wmv",
|
||||
"video/x-ms-wmx",
|
||||
"video/x-ms-wvx",
|
||||
"video/x-nsv",
|
||||
"video/x-ogm+ogg",
|
||||
"video/x-theora+ogg",
|
||||
"video/x-totem-stream",
|
||||
NULL
|
||||
};
|
||||
|
||||
G_GNUC_UNUSED static const gchar *audio_mimetypes[] = {
|
||||
"audio/3gpp",
|
||||
"audio/ac3",
|
||||
"audio/AMR",
|
||||
"audio/AMR-WB",
|
||||
"audio/basic",
|
||||
"audio/flac",
|
||||
"audio/midi",
|
||||
"audio/mp2",
|
||||
"audio/mp4",
|
||||
"audio/mpeg",
|
||||
"audio/ogg",
|
||||
"audio/prs.sid",
|
||||
"audio/vnd.rn-realaudio",
|
||||
"audio/x-aiff",
|
||||
"audio/x-ape",
|
||||
"audio/x-flac",
|
||||
"audio/x-gsm",
|
||||
"audio/x-it",
|
||||
"audio/x-m4a",
|
||||
"audio/x-matroska",
|
||||
"audio/x-mod",
|
||||
"audio/x-mp3",
|
||||
"audio/x-mpeg",
|
||||
"audio/x-ms-asf",
|
||||
"audio/x-ms-asx",
|
||||
"audio/x-ms-wax",
|
||||
"audio/x-ms-wma",
|
||||
"audio/x-musepack",
|
||||
"audio/x-pn-aiff",
|
||||
"audio/x-pn-au",
|
||||
"audio/x-pn-wav",
|
||||
"audio/x-pn-windows-acm",
|
||||
"audio/x-realaudio",
|
||||
"audio/x-real-audio",
|
||||
"audio/x-sbc",
|
||||
"audio/x-speex",
|
||||
"audio/x-tta",
|
||||
"audio/x-wav",
|
||||
"audio/x-wavpack",
|
||||
"audio/x-vorbis",
|
||||
"audio/x-vorbis+ogg",
|
||||
"audio/x-xm",
|
||||
NULL
|
||||
};
|
||||
|
||||
#endif /* __HOTPLUG_MIMETYPES_H__ */
|
319
src/hotplug-sniffer/hotplug-sniffer.c
Normal file
319
src/hotplug-sniffer/hotplug-sniffer.c
Normal file
@ -0,0 +1,319 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Authors: David Zeuthen <davidz@redhat.com>
|
||||
* Cosimo Cecchi <cosimoc@redhat.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shell-mime-sniffer.h"
|
||||
#include "hotplug-mimetypes.h"
|
||||
|
||||
/* Set the environment variable HOTPLUG_SNIFFER_DEBUG to show debug */
|
||||
static void print_debug (const gchar *str, ...);
|
||||
|
||||
#define BUS_NAME "org.gnome.Shell.HotplugSniffer"
|
||||
#define AUTOQUIT_TIMEOUT 5
|
||||
|
||||
static const gchar introspection_xml[] =
|
||||
"<node>"
|
||||
" <interface name='org.gnome.Shell.HotplugSniffer'>"
|
||||
" <method name='SniffURI'>"
|
||||
" <arg type='s' name='uri' direction='in'/>"
|
||||
" <arg type='as' name='content_types' direction='out'/>"
|
||||
" </method>"
|
||||
" </interface>"
|
||||
"</node>";
|
||||
|
||||
static GDBusNodeInfo *introspection_data = NULL;
|
||||
static GMainLoop *loop = NULL;
|
||||
static guint autoquit_id = 0;
|
||||
|
||||
static gboolean
|
||||
autoquit_timeout_cb (gpointer _unused)
|
||||
{
|
||||
print_debug ("Timeout reached, quitting...");
|
||||
|
||||
autoquit_id = 0;
|
||||
g_main_loop_quit (loop);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_autoquit_off (void)
|
||||
{
|
||||
if (g_getenv ("HOTPLUG_SNIFFER_PERSIST") != NULL)
|
||||
return;
|
||||
|
||||
if (autoquit_id != 0)
|
||||
{
|
||||
g_source_remove (autoquit_id);
|
||||
autoquit_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_autoquit_on (void)
|
||||
{
|
||||
if (g_getenv ("HOTPLUG_SNIFFER_PERSIST") != NULL)
|
||||
return;
|
||||
|
||||
autoquit_id =
|
||||
g_timeout_add_seconds (AUTOQUIT_TIMEOUT,
|
||||
autoquit_timeout_cb, NULL);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
GVariant *parameters;
|
||||
GDBusMethodInvocation *invocation;
|
||||
} InvocationData;
|
||||
|
||||
static InvocationData *
|
||||
invocation_data_new (GVariant *params,
|
||||
GDBusMethodInvocation *invocation)
|
||||
{
|
||||
InvocationData *ret;
|
||||
|
||||
ret = g_slice_new0 (InvocationData);
|
||||
ret->parameters = g_variant_ref (params);
|
||||
ret->invocation = g_object_ref (invocation);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
invocation_data_free (InvocationData *data)
|
||||
{
|
||||
g_variant_unref (data->parameters);
|
||||
g_clear_object (&data->invocation);
|
||||
|
||||
g_slice_free (InvocationData, data);
|
||||
}
|
||||
|
||||
static void
|
||||
sniff_async_ready_cb (GObject *source,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
InvocationData *data = user_data;
|
||||
gchar **types;
|
||||
gint idx;
|
||||
GError *error = NULL;
|
||||
GVariantBuilder *builder;
|
||||
GVariant *result;
|
||||
|
||||
types = shell_mime_sniffer_sniff_finish (SHELL_MIME_SNIFFER (source),
|
||||
res, &error);
|
||||
|
||||
if (error != NULL)
|
||||
{
|
||||
g_dbus_method_invocation_return_gerror (data->invocation, error);
|
||||
g_error_free (error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
|
||||
|
||||
for (idx = 0; types[idx] != NULL; idx++)
|
||||
g_variant_builder_add (builder, "s", types[idx]);
|
||||
|
||||
result = g_variant_new ("(as)", builder);
|
||||
g_dbus_method_invocation_return_value (data->invocation, result);
|
||||
|
||||
g_variant_unref (result);
|
||||
g_variant_builder_unref (builder);
|
||||
g_strfreev (types);
|
||||
|
||||
out:
|
||||
invocation_data_free (data);
|
||||
ensure_autoquit_on ();
|
||||
}
|
||||
|
||||
static void
|
||||
handle_sniff_uri (InvocationData *data)
|
||||
{
|
||||
ShellMimeSniffer *sniffer;
|
||||
const gchar *uri;
|
||||
GFile *file;
|
||||
|
||||
ensure_autoquit_off ();
|
||||
|
||||
g_variant_get (data->parameters,
|
||||
"(&s)", &uri,
|
||||
NULL);
|
||||
file = g_file_new_for_uri (uri);
|
||||
|
||||
print_debug ("Initiating sniff for uri %s", uri);
|
||||
|
||||
sniffer = shell_mime_sniffer_new (file);
|
||||
shell_mime_sniffer_sniff_async (sniffer,
|
||||
sniff_async_ready_cb,
|
||||
data);
|
||||
|
||||
g_object_unref (sniffer);
|
||||
g_object_unref (file);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_method_call (GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *method_name,
|
||||
GVariant *parameters,
|
||||
GDBusMethodInvocation *invocation,
|
||||
gpointer user_data)
|
||||
{
|
||||
InvocationData *data;
|
||||
|
||||
data = invocation_data_new (parameters, invocation);
|
||||
|
||||
if (g_strcmp0 (method_name, "SniffURI") == 0)
|
||||
handle_sniff_uri (data);
|
||||
else
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static const GDBusInterfaceVTable interface_vtable =
|
||||
{
|
||||
handle_method_call,
|
||||
NULL, /* get_property */
|
||||
NULL, /* set_property */
|
||||
};
|
||||
|
||||
static void
|
||||
on_bus_acquired (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
print_debug ("Connected to the session bus: %s", name);
|
||||
|
||||
g_dbus_connection_register_object (connection,
|
||||
"/org/gnome/Shell/HotplugSniffer",
|
||||
introspection_data->interfaces[0],
|
||||
&interface_vtable,
|
||||
NULL,
|
||||
NULL,
|
||||
&error);
|
||||
|
||||
if (error != NULL)
|
||||
{
|
||||
g_printerr ("Error exporting object on the session bus: %s",
|
||||
error->message);
|
||||
g_error_free (error);
|
||||
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
print_debug ("Object exported on the session bus");
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_lost (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
print_debug ("Lost bus name: %s, exiting", name);
|
||||
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_acquired (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
print_debug ("Acquired bus name: %s", name);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char **argv)
|
||||
{
|
||||
guint name_owner_id;
|
||||
|
||||
g_type_init ();
|
||||
|
||||
introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
|
||||
g_assert (introspection_data != NULL);
|
||||
|
||||
ensure_autoquit_on ();
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
name_owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
|
||||
BUS_NAME, 0,
|
||||
on_bus_acquired,
|
||||
on_name_acquired,
|
||||
on_name_lost,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
g_main_loop_run (loop);
|
||||
|
||||
if (name_owner_id != 0)
|
||||
g_bus_unown_name (name_owner_id);
|
||||
|
||||
if (loop != NULL)
|
||||
g_main_loop_unref (loop);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
print_debug (const gchar *format, ...)
|
||||
{
|
||||
gchar *s;
|
||||
va_list ap;
|
||||
gchar timebuf[64];
|
||||
GTimeVal now;
|
||||
time_t now_t;
|
||||
struct tm broken_down;
|
||||
static volatile gsize once_init_value = 0;
|
||||
static gboolean show_debug = FALSE;
|
||||
static guint pid = 0;
|
||||
|
||||
if (g_once_init_enter (&once_init_value))
|
||||
{
|
||||
show_debug = (g_getenv ("HOTPLUG_SNIFFER_DEBUG") != NULL);
|
||||
pid = getpid ();
|
||||
g_once_init_leave (&once_init_value, 1);
|
||||
}
|
||||
|
||||
if (!show_debug)
|
||||
goto out;
|
||||
|
||||
g_get_current_time (&now);
|
||||
now_t = now.tv_sec;
|
||||
localtime_r (&now_t, &broken_down);
|
||||
strftime (timebuf, sizeof timebuf, "%H:%M:%S", &broken_down);
|
||||
|
||||
va_start (ap, format);
|
||||
s = g_strdup_vprintf (format, ap);
|
||||
va_end (ap);
|
||||
|
||||
g_print ("gnome-shell-hotplug-sniffer[%d]: %s.%03d: %s\n", pid, timebuf, (gint) (now.tv_usec / 1000), s);
|
||||
g_free (s);
|
||||
out:
|
||||
;
|
||||
}
|
||||
|
@ -0,0 +1,3 @@
|
||||
[D-BUS Service]
|
||||
Name=org.gnome.Shell.HotplugSniffer
|
||||
Exec=@libexecdir@/gnome-shell-hotplug-sniffer
|
607
src/hotplug-sniffer/shell-mime-sniffer.c
Normal file
607
src/hotplug-sniffer/shell-mime-sniffer.c
Normal file
@ -0,0 +1,607 @@
|
||||
/*
|
||||
* Copyright (C) 1999, 2000, 2001 Eazel, Inc.
|
||||
* Copyright (C) 2011 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Author: Cosimo Cecchi <cosimoc@redhat.com>
|
||||
*
|
||||
* The code for crawling the directory hierarchy is based on
|
||||
* nautilus/libnautilus-private/nautilus-directory-async.c, with
|
||||
* the following copyright and author:
|
||||
*
|
||||
* Copyright (C) 1999, 2000, 2001 Eazel, Inc.
|
||||
* Author: Darin Adler <darin@bentspoon.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shell-mime-sniffer.h"
|
||||
#include "hotplug-mimetypes.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
#define LOADER_ATTRS \
|
||||
G_FILE_ATTRIBUTE_STANDARD_TYPE "," \
|
||||
G_FILE_ATTRIBUTE_STANDARD_NAME "," \
|
||||
G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE ","
|
||||
|
||||
#define WATCHDOG_TIMEOUT 1500
|
||||
#define DIRECTORY_LOAD_ITEMS_PER_CALLBACK 100
|
||||
#define HIGH_SCORE_RATIO 0.10
|
||||
|
||||
G_DEFINE_TYPE (ShellMimeSniffer, shell_mime_sniffer, G_TYPE_OBJECT);
|
||||
|
||||
enum {
|
||||
PROP_FILE = 1,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
static GHashTable *image_type_table = NULL;
|
||||
static GHashTable *audio_type_table = NULL;
|
||||
static GHashTable *video_type_table = NULL;
|
||||
static GHashTable *docs_type_table = NULL;
|
||||
|
||||
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
|
||||
|
||||
typedef struct {
|
||||
ShellMimeSniffer *self;
|
||||
|
||||
GFile *file;
|
||||
GFileEnumerator *enumerator;
|
||||
GList *deep_count_subdirectories;
|
||||
|
||||
gint audio_count;
|
||||
gint image_count;
|
||||
gint document_count;
|
||||
gint video_count;
|
||||
|
||||
gint total_items;
|
||||
} DeepCountState;
|
||||
|
||||
struct _ShellMimeSnifferPrivate {
|
||||
GFile *file;
|
||||
|
||||
GCancellable *cancellable;
|
||||
guint watchdog_id;
|
||||
|
||||
GSimpleAsyncResult *async_result;
|
||||
gchar **sniffed_mime;
|
||||
};
|
||||
|
||||
static void deep_count_load (DeepCountState *state,
|
||||
GFile *file);
|
||||
|
||||
static void
|
||||
init_mimetypes (void)
|
||||
{
|
||||
static gsize once_init = 0;
|
||||
|
||||
if (g_once_init_enter (&once_init))
|
||||
{
|
||||
GSList *formats, *l;
|
||||
GdkPixbufFormat *format;
|
||||
gchar **types;
|
||||
gint idx;
|
||||
|
||||
image_type_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||
video_type_table = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
audio_type_table = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
docs_type_table = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
|
||||
formats = gdk_pixbuf_get_formats ();
|
||||
|
||||
for (l = formats; l != NULL; l = l->next)
|
||||
{
|
||||
format = l->data;
|
||||
types = gdk_pixbuf_format_get_mime_types (format);
|
||||
|
||||
for (idx = 0; types[idx] != NULL; idx++)
|
||||
g_hash_table_insert (image_type_table, g_strdup (types[idx]), GINT_TO_POINTER (1));
|
||||
|
||||
g_strfreev (types);
|
||||
}
|
||||
|
||||
g_slist_free (formats);
|
||||
|
||||
for (idx = 0; audio_mimetypes[idx] != NULL; idx++)
|
||||
g_hash_table_insert (audio_type_table, (gpointer) audio_mimetypes[idx], GINT_TO_POINTER (1));
|
||||
|
||||
for (idx = 0; video_mimetypes[idx] != NULL; idx++)
|
||||
g_hash_table_insert (video_type_table, (gpointer) video_mimetypes[idx], GINT_TO_POINTER (1));
|
||||
|
||||
for (idx = 0; docs_mimetypes[idx] != NULL; idx++)
|
||||
g_hash_table_insert (docs_type_table, (gpointer) docs_mimetypes[idx], GINT_TO_POINTER (1));
|
||||
|
||||
g_once_init_leave (&once_init, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_content_type_to_cache (DeepCountState *state,
|
||||
const gchar *content_type)
|
||||
{
|
||||
gboolean matched = TRUE;
|
||||
|
||||
if (g_hash_table_lookup (image_type_table, content_type))
|
||||
state->image_count++;
|
||||
else if (g_hash_table_lookup (video_type_table, content_type))
|
||||
state->video_count++;
|
||||
else if (g_hash_table_lookup (docs_type_table, content_type))
|
||||
state->document_count++;
|
||||
else if (g_hash_table_lookup (audio_type_table, content_type))
|
||||
state->audio_count++;
|
||||
else
|
||||
matched = FALSE;
|
||||
|
||||
if (matched)
|
||||
state->total_items++;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const gchar *type;
|
||||
gdouble ratio;
|
||||
} SniffedResult;
|
||||
|
||||
static gint
|
||||
results_cmp_func (gconstpointer a,
|
||||
gconstpointer b)
|
||||
{
|
||||
const SniffedResult *sniffed_a = a;
|
||||
const SniffedResult *sniffed_b = b;
|
||||
|
||||
if (sniffed_a->ratio < sniffed_b->ratio)
|
||||
return 1;
|
||||
|
||||
if (sniffed_a->ratio > sniffed_b->ratio)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
prepare_async_result (DeepCountState *state)
|
||||
{
|
||||
ShellMimeSniffer *self = state->self;
|
||||
GArray *results;
|
||||
GPtrArray *sniffed_mime;
|
||||
SniffedResult result;
|
||||
|
||||
sniffed_mime = g_ptr_array_new ();
|
||||
results = g_array_new (TRUE, TRUE, sizeof (SniffedResult));
|
||||
|
||||
if (state->total_items == 0)
|
||||
goto out;
|
||||
|
||||
result.type = "x-content/video";
|
||||
result.ratio = (gdouble) state->video_count / (gdouble) state->total_items;
|
||||
g_array_append_val (results, result);
|
||||
|
||||
result.type = "x-content/audio";
|
||||
result.ratio = (gdouble) state->audio_count / (gdouble) state->total_items;
|
||||
g_array_append_val (results, result);
|
||||
|
||||
result.type = "x-content/pictures";
|
||||
result.ratio = (gdouble) state->image_count / (gdouble) state->total_items;
|
||||
g_array_append_val (results, result);
|
||||
|
||||
result.type = "x-content/documents";
|
||||
result.ratio = (gdouble) state->document_count / (gdouble) state->total_items;
|
||||
g_array_append_val (results, result);
|
||||
|
||||
g_array_sort (results, results_cmp_func);
|
||||
|
||||
result = g_array_index (results, SniffedResult, 0);
|
||||
g_ptr_array_add (sniffed_mime, g_strdup (result.type));
|
||||
|
||||
/* if other types score high in ratio, add them, up to three */
|
||||
result = g_array_index (results, SniffedResult, 1);
|
||||
if (result.ratio < HIGH_SCORE_RATIO)
|
||||
goto out;
|
||||
g_ptr_array_add (sniffed_mime, g_strdup (result.type));
|
||||
|
||||
result = g_array_index (results, SniffedResult, 2);
|
||||
if (result.ratio < HIGH_SCORE_RATIO)
|
||||
goto out;
|
||||
g_ptr_array_add (sniffed_mime, g_strdup (result.type));
|
||||
|
||||
out:
|
||||
g_ptr_array_add (sniffed_mime, NULL);
|
||||
self->priv->sniffed_mime = (gchar **) g_ptr_array_free (sniffed_mime, FALSE);
|
||||
|
||||
g_array_free (results, TRUE);
|
||||
g_simple_async_result_complete_in_idle (self->priv->async_result);
|
||||
}
|
||||
|
||||
/* adapted from nautilus/libnautilus-private/nautilus-directory-async.c */
|
||||
static void
|
||||
deep_count_one (DeepCountState *state,
|
||||
GFileInfo *info)
|
||||
{
|
||||
GFile *subdir;
|
||||
const char *content_type;
|
||||
|
||||
if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
|
||||
{
|
||||
/* record the fact that we have to descend into this directory */
|
||||
subdir = g_file_get_child (state->file, g_file_info_get_name (info));
|
||||
state->deep_count_subdirectories =
|
||||
g_list_append (state->deep_count_subdirectories, subdir);
|
||||
}
|
||||
else
|
||||
{
|
||||
content_type = g_file_info_get_content_type (info);
|
||||
add_content_type_to_cache (state, content_type);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
deep_count_finish (DeepCountState *state)
|
||||
{
|
||||
prepare_async_result (state);
|
||||
|
||||
if (state->enumerator)
|
||||
{
|
||||
if (!g_file_enumerator_is_closed (state->enumerator))
|
||||
g_file_enumerator_close_async (state->enumerator,
|
||||
0, NULL, NULL, NULL);
|
||||
|
||||
g_object_unref (state->enumerator);
|
||||
}
|
||||
|
||||
g_cancellable_reset (state->self->priv->cancellable);
|
||||
g_clear_object (&state->file);
|
||||
|
||||
g_list_free_full (state->deep_count_subdirectories, g_object_unref);
|
||||
|
||||
g_free (state);
|
||||
}
|
||||
|
||||
static void
|
||||
deep_count_next_dir (DeepCountState *state)
|
||||
{
|
||||
GFile *new_file;
|
||||
|
||||
g_clear_object (&state->file);
|
||||
|
||||
if (state->deep_count_subdirectories != NULL)
|
||||
{
|
||||
/* Work on a new directory. */
|
||||
new_file = state->deep_count_subdirectories->data;
|
||||
state->deep_count_subdirectories =
|
||||
g_list_remove (state->deep_count_subdirectories, new_file);
|
||||
|
||||
deep_count_load (state, new_file);
|
||||
g_object_unref (new_file);
|
||||
}
|
||||
else
|
||||
{
|
||||
deep_count_finish (state);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
deep_count_more_files_callback (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
DeepCountState *state;
|
||||
GList *files, *l;
|
||||
GFileInfo *info;
|
||||
|
||||
state = user_data;
|
||||
|
||||
if (g_cancellable_is_cancelled (state->self->priv->cancellable))
|
||||
{
|
||||
deep_count_finish (state);
|
||||
return;
|
||||
}
|
||||
|
||||
files = g_file_enumerator_next_files_finish (state->enumerator,
|
||||
res, NULL);
|
||||
|
||||
for (l = files; l != NULL; l = l->next)
|
||||
{
|
||||
info = l->data;
|
||||
deep_count_one (state, info);
|
||||
g_object_unref (info);
|
||||
}
|
||||
|
||||
if (files == NULL)
|
||||
{
|
||||
g_file_enumerator_close_async (state->enumerator, 0, NULL, NULL, NULL);
|
||||
g_object_unref (state->enumerator);
|
||||
state->enumerator = NULL;
|
||||
|
||||
deep_count_next_dir (state);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_file_enumerator_next_files_async (state->enumerator,
|
||||
DIRECTORY_LOAD_ITEMS_PER_CALLBACK,
|
||||
G_PRIORITY_LOW,
|
||||
state->self->priv->cancellable,
|
||||
deep_count_more_files_callback,
|
||||
state);
|
||||
}
|
||||
|
||||
g_list_free (files);
|
||||
}
|
||||
|
||||
static void
|
||||
deep_count_callback (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
DeepCountState *state;
|
||||
GFileEnumerator *enumerator;
|
||||
|
||||
state = user_data;
|
||||
|
||||
if (g_cancellable_is_cancelled (state->self->priv->cancellable))
|
||||
{
|
||||
deep_count_finish (state);
|
||||
return;
|
||||
}
|
||||
|
||||
enumerator = g_file_enumerate_children_finish (G_FILE (source_object),
|
||||
res, NULL);
|
||||
|
||||
if (enumerator == NULL)
|
||||
{
|
||||
deep_count_next_dir (state);
|
||||
}
|
||||
else
|
||||
{
|
||||
state->enumerator = enumerator;
|
||||
g_file_enumerator_next_files_async (state->enumerator,
|
||||
DIRECTORY_LOAD_ITEMS_PER_CALLBACK,
|
||||
G_PRIORITY_LOW,
|
||||
state->self->priv->cancellable,
|
||||
deep_count_more_files_callback,
|
||||
state);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
deep_count_load (DeepCountState *state,
|
||||
GFile *file)
|
||||
{
|
||||
state->file = g_object_ref (file);
|
||||
|
||||
g_file_enumerate_children_async (state->file,
|
||||
LOADER_ATTRS,
|
||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, /* flags */
|
||||
G_PRIORITY_LOW, /* prio */
|
||||
state->self->priv->cancellable,
|
||||
deep_count_callback,
|
||||
state);
|
||||
}
|
||||
|
||||
static void
|
||||
deep_count_start (ShellMimeSniffer *self)
|
||||
{
|
||||
DeepCountState *state;
|
||||
|
||||
state = g_new0 (DeepCountState, 1);
|
||||
state->self = self;
|
||||
|
||||
deep_count_load (state, self->priv->file);
|
||||
}
|
||||
|
||||
static void
|
||||
query_info_async_ready_cb (GObject *source,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
GFileInfo *info;
|
||||
GError *error = NULL;
|
||||
ShellMimeSniffer *self = user_data;
|
||||
|
||||
info = g_file_query_info_finish (G_FILE (source),
|
||||
res, &error);
|
||||
|
||||
if (error != NULL)
|
||||
{
|
||||
g_simple_async_result_take_error (self->priv->async_result,
|
||||
error);
|
||||
g_simple_async_result_complete_in_idle (self->priv->async_result);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_file_info_get_file_type (info) != G_FILE_TYPE_DIRECTORY)
|
||||
{
|
||||
g_simple_async_result_set_error (self->priv->async_result,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_NOT_DIRECTORY,
|
||||
"Not a directory");
|
||||
g_simple_async_result_complete_in_idle (self->priv->async_result);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
deep_count_start (self);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
watchdog_timeout_reached_cb (gpointer user_data)
|
||||
{
|
||||
ShellMimeSniffer *self = user_data;
|
||||
|
||||
self->priv->watchdog_id = 0;
|
||||
g_cancellable_cancel (self->priv->cancellable);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
start_loading_file (ShellMimeSniffer *self)
|
||||
{
|
||||
g_file_query_info_async (self->priv->file,
|
||||
LOADER_ATTRS,
|
||||
G_FILE_QUERY_INFO_NONE,
|
||||
G_PRIORITY_DEFAULT,
|
||||
self->priv->cancellable,
|
||||
query_info_async_ready_cb,
|
||||
self);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_mime_sniffer_set_file (ShellMimeSniffer *self,
|
||||
GFile *file)
|
||||
{
|
||||
g_clear_object (&self->priv->file);
|
||||
self->priv->file = g_object_ref (file);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_mime_sniffer_dispose (GObject *object)
|
||||
{
|
||||
ShellMimeSniffer *self = SHELL_MIME_SNIFFER (object);
|
||||
|
||||
g_clear_object (&self->priv->file);
|
||||
g_clear_object (&self->priv->cancellable);
|
||||
g_clear_object (&self->priv->async_result);
|
||||
|
||||
if (self->priv->watchdog_id != 0)
|
||||
{
|
||||
g_source_remove (self->priv->watchdog_id);
|
||||
self->priv->watchdog_id = 0;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (shell_mime_sniffer_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_mime_sniffer_finalize (GObject *object)
|
||||
{
|
||||
ShellMimeSniffer *self = SHELL_MIME_SNIFFER (object);
|
||||
|
||||
g_strfreev (self->priv->sniffed_mime);
|
||||
|
||||
G_OBJECT_CLASS (shell_mime_sniffer_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_mime_sniffer_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ShellMimeSniffer *self = SHELL_MIME_SNIFFER (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_FILE:
|
||||
g_value_set_object (value, self->priv->file);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
shell_mime_sniffer_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ShellMimeSniffer *self = SHELL_MIME_SNIFFER (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_FILE:
|
||||
shell_mime_sniffer_set_file (self, g_value_get_object (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
shell_mime_sniffer_class_init (ShellMimeSnifferClass *klass)
|
||||
{
|
||||
GObjectClass *oclass;
|
||||
|
||||
oclass = G_OBJECT_CLASS (klass);
|
||||
oclass->dispose = shell_mime_sniffer_dispose;
|
||||
oclass->finalize = shell_mime_sniffer_finalize;
|
||||
oclass->get_property = shell_mime_sniffer_get_property;
|
||||
oclass->set_property = shell_mime_sniffer_set_property;
|
||||
|
||||
properties[PROP_FILE] =
|
||||
g_param_spec_object ("file",
|
||||
"File",
|
||||
"The loaded file",
|
||||
G_TYPE_FILE,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
g_type_class_add_private (klass, sizeof (ShellMimeSnifferPrivate));
|
||||
g_object_class_install_properties (oclass, NUM_PROPERTIES, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_mime_sniffer_init (ShellMimeSniffer *self)
|
||||
{
|
||||
self->priv =
|
||||
G_TYPE_INSTANCE_GET_PRIVATE (self,
|
||||
SHELL_TYPE_MIME_SNIFFER,
|
||||
ShellMimeSnifferPrivate);
|
||||
init_mimetypes ();
|
||||
}
|
||||
|
||||
ShellMimeSniffer *
|
||||
shell_mime_sniffer_new (GFile *file)
|
||||
{
|
||||
return g_object_new (SHELL_TYPE_MIME_SNIFFER,
|
||||
"file", file,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
shell_mime_sniffer_sniff_async (ShellMimeSniffer *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_assert (self->priv->watchdog_id == 0);
|
||||
g_assert (self->priv->async_result == NULL);
|
||||
|
||||
self->priv->async_result =
|
||||
g_simple_async_result_new (G_OBJECT (self),
|
||||
callback, user_data,
|
||||
shell_mime_sniffer_sniff_finish);
|
||||
|
||||
self->priv->cancellable = g_cancellable_new ();
|
||||
|
||||
self->priv->watchdog_id =
|
||||
g_timeout_add (WATCHDOG_TIMEOUT,
|
||||
watchdog_timeout_reached_cb, self);
|
||||
|
||||
start_loading_file (self);
|
||||
}
|
||||
|
||||
gchar **
|
||||
shell_mime_sniffer_sniff_finish (ShellMimeSniffer *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
if (g_simple_async_result_propagate_error (self->priv->async_result, error))
|
||||
return NULL;
|
||||
|
||||
return g_strdupv (self->priv->sniffed_mime);
|
||||
}
|
68
src/hotplug-sniffer/shell-mime-sniffer.h
Normal file
68
src/hotplug-sniffer/shell-mime-sniffer.h
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Author: Cosimo Cecchi <cosimoc@redhat.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SHELL_MIME_SNIFFER_H__
|
||||
#define __SHELL_MIME_SNIFFER_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SHELL_TYPE_MIME_SNIFFER (shell_mime_sniffer_get_type ())
|
||||
#define SHELL_MIME_SNIFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_MIME_SNIFFER, ShellMimeSniffer))
|
||||
#define SHELL_IS_MIME_SNIFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SHELL_TYPE_MIME_SNIFFER))
|
||||
#define SHELL_MIME_SNIFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_MIME_SNIFFER, ShellMimeSnifferClass))
|
||||
#define SHELL_IS_MIME_SNIFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_MIME_SNIFFER))
|
||||
#define SHELL_MIME_SNIFFER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_MIME_SNIFFER, ShellMimeSnifferClass))
|
||||
|
||||
typedef struct _ShellMimeSniffer ShellMimeSniffer;
|
||||
typedef struct _ShellMimeSnifferPrivate ShellMimeSnifferPrivate;
|
||||
typedef struct _ShellMimeSnifferClass ShellMimeSnifferClass;
|
||||
|
||||
struct _ShellMimeSniffer
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
ShellMimeSnifferPrivate *priv;
|
||||
};
|
||||
|
||||
struct _ShellMimeSnifferClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
GType shell_mime_sniffer_get_type (void) G_GNUC_CONST;
|
||||
|
||||
ShellMimeSniffer *shell_mime_sniffer_new (GFile *file);
|
||||
|
||||
void shell_mime_sniffer_sniff_async (ShellMimeSniffer *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
|
||||
gchar ** shell_mime_sniffer_sniff_finish (ShellMimeSniffer *self,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __SHELL_MIME_SNIFFER_H__ */
|
36
src/main.c
36
src/main.c
@ -19,6 +19,8 @@
|
||||
#include <meta/main.h>
|
||||
#include <meta/meta-plugin.h>
|
||||
#include <meta/prefs.h>
|
||||
#include <telepathy-glib/debug.h>
|
||||
#include <telepathy-glib/debug-sender.h>
|
||||
|
||||
#include "shell-a11y.h"
|
||||
#include "shell-global.h"
|
||||
@ -428,6 +430,25 @@ muted_log_handler (const char *log_domain,
|
||||
/* Intentionally empty to discard message */
|
||||
}
|
||||
|
||||
static void
|
||||
default_log_handler (const char *log_domain,
|
||||
GLogLevelFlags log_level,
|
||||
const char *message,
|
||||
gpointer data)
|
||||
{
|
||||
TpDebugSender *sender = data;
|
||||
GTimeVal now;
|
||||
|
||||
g_get_current_time (&now);
|
||||
|
||||
tp_debug_sender_add_message (sender, &now, log_domain, log_level, message);
|
||||
|
||||
/* Filter out telepathy-glib logs, we don't want to flood Shell's output
|
||||
* with those. */
|
||||
if (!g_str_has_prefix (log_domain, "tp-glib"))
|
||||
g_log_default_handler (log_domain, log_level, message, data);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
print_version (const gchar *option_name,
|
||||
const gchar *value,
|
||||
@ -454,6 +475,7 @@ main (int argc, char **argv)
|
||||
GOptionContext *ctx;
|
||||
GError *error = NULL;
|
||||
int ecode;
|
||||
TpDebugSender *sender;
|
||||
|
||||
g_type_init ();
|
||||
|
||||
@ -469,6 +491,8 @@ main (int argc, char **argv)
|
||||
exit (1);
|
||||
}
|
||||
|
||||
g_option_context_free (ctx);
|
||||
|
||||
meta_plugin_type_register (gnome_shell_plugin_get_type ());
|
||||
|
||||
/* Prevent meta_init() from causing gtk to load gail and at-bridge */
|
||||
@ -504,6 +528,16 @@ main (int argc, char **argv)
|
||||
muted_log_handler, NULL);
|
||||
g_log_set_handler ("Bluetooth", G_LOG_LEVEL_DEBUG | G_LOG_LEVEL_MESSAGE,
|
||||
muted_log_handler, NULL);
|
||||
g_log_set_handler ("tp-glib/proxy", G_LOG_LEVEL_DEBUG,
|
||||
muted_log_handler, NULL);
|
||||
|
||||
/* Turn on telepathy-glib debugging but filter it out in
|
||||
* default_log_handler. This handler also exposes all the logs over D-Bus
|
||||
* using TpDebugSender. */
|
||||
tp_debug_set_flags ("all");
|
||||
|
||||
sender = tp_debug_sender_dup ();
|
||||
g_log_set_default_handler (default_log_handler, sender);
|
||||
|
||||
/* Initialize the global object */
|
||||
shell_global_get ();
|
||||
@ -516,5 +550,7 @@ main (int argc, char **argv)
|
||||
g_object_unref (shell_global_get ());
|
||||
}
|
||||
|
||||
g_object_unref (sender);
|
||||
|
||||
return ecode;
|
||||
}
|
||||
|
@ -32,18 +32,17 @@
|
||||
|
||||
#include <clutter/x11/clutter-x11.h>
|
||||
#include <gdk/gdkx.h>
|
||||
#include <girepository.h>
|
||||
#include <gjs/gjs.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "shell-global.h"
|
||||
#include "shell-global-private.h"
|
||||
|
||||
static char **include_path = NULL;
|
||||
static char *command = NULL;
|
||||
|
||||
static GOptionEntry entries[] = {
|
||||
{ "command", 'c', 0, G_OPTION_ARG_STRING, &command, "Program passed in as a string", "COMMAND" },
|
||||
{ "include-path", 'I', 0, G_OPTION_ARG_STRING_ARRAY, &include_path, "Add the directory DIR to the list of directories to search for js files.", "DIR" },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@ -131,6 +130,14 @@ main(int argc, char **argv)
|
||||
clutter_stage_set_title (CLUTTER_STAGE (stage), title);
|
||||
g_free (title);
|
||||
|
||||
#if HAVE_BLUETOOTH
|
||||
/* The module imports are all so intertwined that if the test
|
||||
* imports anything in js/ui, it will probably eventually end up
|
||||
* pulling in ui/status/bluetooth.js. So we need this.
|
||||
*/
|
||||
g_irepository_prepend_search_path (BLUETOOTH_DIR);
|
||||
#endif
|
||||
|
||||
/* evaluate the script */
|
||||
error = NULL;
|
||||
if (!gjs_context_eval (js_context, script, len,
|
||||
|
@ -1193,109 +1193,6 @@ void shell_global_init_xdnd (ShellGlobal *global)
|
||||
32, PropModeReplace, (const unsigned char *)&stage_win, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_global_get_monitors:
|
||||
* @global: the #ShellGlobal
|
||||
*
|
||||
* Gets a list of the bounding boxes of the active screen's monitors.
|
||||
*
|
||||
* Return value: (transfer full) (element-type Meta.Rectangle): a list
|
||||
* of monitor bounding boxes.
|
||||
*/
|
||||
GSList *
|
||||
shell_global_get_monitors (ShellGlobal *global)
|
||||
{
|
||||
MetaScreen *screen = shell_global_get_screen (global);
|
||||
GSList *monitors = NULL;
|
||||
MetaRectangle rect;
|
||||
int i;
|
||||
|
||||
for (i = meta_screen_get_n_monitors (screen) - 1; i >= 0; i--)
|
||||
{
|
||||
meta_screen_get_monitor_geometry (screen, i, &rect);
|
||||
monitors = g_slist_prepend (monitors,
|
||||
meta_rectangle_copy (&rect));
|
||||
}
|
||||
return monitors;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_global_get_primary_monitor:
|
||||
* @global: the #ShellGlobal
|
||||
*
|
||||
* Gets the bounding box of the primary monitor (the one that the
|
||||
* panel is on).
|
||||
*
|
||||
* Return value: the bounding box of the primary monitor
|
||||
*/
|
||||
MetaRectangle *
|
||||
shell_global_get_primary_monitor (ShellGlobal *global)
|
||||
{
|
||||
MetaScreen *screen = shell_global_get_screen (global);
|
||||
MetaRectangle rect;
|
||||
gint primary = 0;
|
||||
|
||||
primary = meta_screen_get_primary_monitor (screen);
|
||||
meta_screen_get_monitor_geometry (screen, primary, &rect);
|
||||
|
||||
return meta_rectangle_copy (&rect);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_global_get_primary_monitor_index:
|
||||
* @global: the #ShellGlobal
|
||||
*
|
||||
* Gets the index of the primary monitor (the one that the
|
||||
* panel is on).
|
||||
*
|
||||
* Return value: the index of the primary monitor
|
||||
*/
|
||||
int
|
||||
shell_global_get_primary_monitor_index (ShellGlobal *global)
|
||||
{
|
||||
MetaScreen *screen = shell_global_get_screen (global);
|
||||
|
||||
return meta_screen_get_primary_monitor (screen);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_global_get_focus_monitor:
|
||||
* @global: the #ShellGlobal
|
||||
*
|
||||
* Gets the bounding box of the monitor containing the window that
|
||||
* currently contains the keyboard focus.
|
||||
*
|
||||
* Return value: the bounding box of the focus monitor
|
||||
*/
|
||||
MetaRectangle *
|
||||
shell_global_get_focus_monitor (ShellGlobal *global)
|
||||
{
|
||||
MetaScreen *screen = shell_global_get_screen (global);
|
||||
MetaDisplay *display = meta_screen_get_display (screen);
|
||||
MetaWindow *focus = meta_display_get_focus_window (display);
|
||||
MetaRectangle rect, wrect;
|
||||
int nmonitors, i;
|
||||
|
||||
if (focus)
|
||||
{
|
||||
meta_window_get_outer_rect (focus, &wrect);
|
||||
nmonitors = meta_screen_get_n_monitors (screen);
|
||||
|
||||
/* Find the monitor that the top-left corner of @focus is on. */
|
||||
for (i = 0; i < nmonitors; i++)
|
||||
{
|
||||
meta_screen_get_monitor_geometry (screen, i, &rect);
|
||||
|
||||
if (rect.x <= wrect.x && rect.y <= wrect.y &&
|
||||
rect.x + rect.width > wrect.x &&
|
||||
rect.y + rect.height > wrect.y)
|
||||
return meta_rectangle_copy (&rect);
|
||||
}
|
||||
}
|
||||
|
||||
return shell_global_get_primary_monitor (global);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_global_get_pointer:
|
||||
* @global: the #ShellGlobal
|
||||
|
@ -32,10 +32,6 @@ ShellGlobal *shell_global_get (void);
|
||||
MetaScreen *shell_global_get_screen (ShellGlobal *global);
|
||||
GdkScreen *shell_global_get_gdk_screen (ShellGlobal *global);
|
||||
GList *shell_global_get_window_actors (ShellGlobal *global);
|
||||
GSList *shell_global_get_monitors (ShellGlobal *global);
|
||||
MetaRectangle *shell_global_get_primary_monitor (ShellGlobal *global);
|
||||
int shell_global_get_primary_monitor_index (ShellGlobal *global);
|
||||
MetaRectangle *shell_global_get_focus_monitor (ShellGlobal *global);
|
||||
GSettings *shell_global_get_settings (ShellGlobal *global);
|
||||
guint32 shell_global_get_current_time (ShellGlobal *global);
|
||||
|
||||
|
184
src/shell-mount-operation.c
Normal file
184
src/shell-mount-operation.c
Normal file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Author: Cosimo Cecchi <cosimoc@redhat.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shell-mount-operation.h"
|
||||
|
||||
/* This is a dummy class; we would like to be able to subclass the
|
||||
* object from JS but we can't yet; the default GMountOperation impl
|
||||
* automatically calls g_mount_operation_reply(UNHANDLED) after an idle,
|
||||
* in interactive methods. We want to handle the reply outselves
|
||||
* instead, so we just override the default methods with empty ones,
|
||||
* except for ask-password, as we don't want to handle that.
|
||||
*
|
||||
* Also, we need to workaround the fact that gjs doesn't support type
|
||||
* annotations for signals yet (so we can't effectively forward e.g.
|
||||
* the GPid array to JS).
|
||||
* See https://bugzilla.gnome.org/show_bug.cgi?id=645978
|
||||
*/
|
||||
G_DEFINE_TYPE (ShellMountOperation, shell_mount_operation, G_TYPE_MOUNT_OPERATION);
|
||||
|
||||
enum {
|
||||
SHOW_PROCESSES_2,
|
||||
NUM_SIGNALS
|
||||
};
|
||||
|
||||
static guint signals[NUM_SIGNALS] = { 0, };
|
||||
|
||||
struct _ShellMountOperationPrivate {
|
||||
GArray *pids;
|
||||
gchar **choices;
|
||||
gchar *message;
|
||||
};
|
||||
|
||||
static void
|
||||
shell_mount_operation_init (ShellMountOperation *self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, SHELL_TYPE_MOUNT_OPERATION,
|
||||
ShellMountOperationPrivate);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_mount_operation_ask_password (GMountOperation *op,
|
||||
const char *message,
|
||||
const char *default_user,
|
||||
const char *default_domain,
|
||||
GAskPasswordFlags flags)
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
static void
|
||||
shell_mount_operation_ask_question (GMountOperation *op,
|
||||
const char *message,
|
||||
const char *choices[])
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
static void
|
||||
shell_mount_operation_show_processes (GMountOperation *operation,
|
||||
const gchar *message,
|
||||
GArray *processes,
|
||||
const gchar *choices[])
|
||||
{
|
||||
ShellMountOperation *self = SHELL_MOUNT_OPERATION (operation);
|
||||
|
||||
if (self->priv->pids != NULL)
|
||||
{
|
||||
g_array_unref (self->priv->pids);
|
||||
self->priv->pids = NULL;
|
||||
}
|
||||
|
||||
g_free (self->priv->message);
|
||||
g_strfreev (self->priv->choices);
|
||||
|
||||
/* save the parameters */
|
||||
self->priv->pids = g_array_ref (processes);
|
||||
self->priv->choices = g_strdupv ((gchar **) choices);
|
||||
self->priv->message = g_strdup (message);
|
||||
|
||||
g_signal_emit (self, signals[SHOW_PROCESSES_2], 0);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_mount_operation_finalize (GObject *obj)
|
||||
{
|
||||
ShellMountOperation *self = SHELL_MOUNT_OPERATION (obj);
|
||||
|
||||
g_strfreev (self->priv->choices);
|
||||
g_free (self->priv->message);
|
||||
|
||||
if (self->priv->pids != NULL)
|
||||
{
|
||||
g_array_unref (self->priv->pids);
|
||||
self->priv->pids = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (shell_mount_operation_parent_class)->finalize (obj);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_mount_operation_class_init (ShellMountOperationClass *klass)
|
||||
{
|
||||
GMountOperationClass *mclass;
|
||||
GObjectClass *oclass;
|
||||
|
||||
mclass = G_MOUNT_OPERATION_CLASS (klass);
|
||||
mclass->show_processes = shell_mount_operation_show_processes;
|
||||
mclass->ask_question = shell_mount_operation_ask_question;
|
||||
mclass->ask_password = shell_mount_operation_ask_password;
|
||||
|
||||
oclass = G_OBJECT_CLASS (klass);
|
||||
oclass->finalize = shell_mount_operation_finalize;
|
||||
|
||||
signals[SHOW_PROCESSES_2] =
|
||||
g_signal_new ("show-processes-2",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0, NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
g_type_class_add_private (klass, sizeof (ShellMountOperationPrivate));
|
||||
}
|
||||
|
||||
GMountOperation *
|
||||
shell_mount_operation_new (void)
|
||||
{
|
||||
return g_object_new (SHELL_TYPE_MOUNT_OPERATION, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_mount_operation_get_show_processes_pids:
|
||||
* @self: a #ShellMountOperation
|
||||
*
|
||||
* Returns: (transfer full) (element-type GPid): a #GArray
|
||||
*/
|
||||
GArray *
|
||||
shell_mount_operation_get_show_processes_pids (ShellMountOperation *self)
|
||||
{
|
||||
return g_array_ref (self->priv->pids);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_mount_operation_get_show_processes_choices:
|
||||
* @self: a #ShellMountOperation
|
||||
*
|
||||
* Returns: (transfer full):
|
||||
*/
|
||||
gchar **
|
||||
shell_mount_operation_get_show_processes_choices (ShellMountOperation *self)
|
||||
{
|
||||
return g_strdupv (self->priv->choices);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_mount_operation_get_show_processes_message:
|
||||
* @self: a #ShellMountOperation
|
||||
*
|
||||
* Returns: (transfer full):
|
||||
*/
|
||||
gchar *
|
||||
shell_mount_operation_get_show_processes_message (ShellMountOperation *self)
|
||||
{
|
||||
return g_strdup (self->priv->message);
|
||||
}
|
63
src/shell-mount-operation.h
Normal file
63
src/shell-mount-operation.h
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Author: Cosimo Cecchi <cosimoc@redhat.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SHELL_MOUNT_OPERATION_H__
|
||||
#define __SHELL_MOUNT_OPERATION_H__
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SHELL_TYPE_MOUNT_OPERATION (shell_mount_operation_get_type ())
|
||||
#define SHELL_MOUNT_OPERATION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SHELL_TYPE_MOUNT_OPERATION, ShellMountOperation))
|
||||
#define SHELL_MOUNT_OPERATION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SHELL_TYPE_MOUNT_OPERATION, ShellMountOperationClass))
|
||||
#define SHELL_IS_MOUNT_OPERATION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SHELL_TYPE_MOUNT_OPERATION))
|
||||
#define SHELL_IS_MOUNT_OPERATION_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SHELL_TYPE_MOUNT_OPERATION))
|
||||
#define SHELL_MOUNT_OPERATION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), SHELL_TYPE_MOUNT_OPERATION, ShellMountOperationClass))
|
||||
|
||||
typedef struct _ShellMountOperation ShellMountOperation;
|
||||
typedef struct _ShellMountOperationClass ShellMountOperationClass;
|
||||
typedef struct _ShellMountOperationPrivate ShellMountOperationPrivate;
|
||||
|
||||
struct _ShellMountOperation
|
||||
{
|
||||
GMountOperation parent_instance;
|
||||
|
||||
ShellMountOperationPrivate *priv;
|
||||
};
|
||||
|
||||
struct _ShellMountOperationClass
|
||||
{
|
||||
GMountOperationClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType shell_mount_operation_get_type (void);
|
||||
GMountOperation *shell_mount_operation_new (void);
|
||||
|
||||
GArray * shell_mount_operation_get_show_processes_pids (ShellMountOperation *self);
|
||||
gchar ** shell_mount_operation_get_show_processes_choices (ShellMountOperation *self);
|
||||
gchar * shell_mount_operation_get_show_processes_message (ShellMountOperation *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __SHELL_MOUNT_OPERATION_H__ */
|
@ -198,7 +198,7 @@ create_recording_icon (void)
|
||||
|
||||
texture = cogl_texture_new_from_data (32, 32,
|
||||
COGL_TEXTURE_NONE,
|
||||
COGL_PIXEL_FORMAT_BGRA_8888,
|
||||
CLUTTER_CAIRO_FORMAT_ARGB32,
|
||||
COGL_PIXEL_FORMAT_ANY,
|
||||
cairo_image_surface_get_stride (surface),
|
||||
cairo_image_surface_get_data (surface));
|
||||
@ -529,7 +529,7 @@ recorder_record_frame (ShellRecorder *recorder)
|
||||
cogl_read_pixels (0, 0,
|
||||
recorder->stage_width, recorder->stage_height,
|
||||
COGL_READ_PIXELS_COLOR_BUFFER,
|
||||
COGL_PIXEL_FORMAT_BGRA_8888_PRE,
|
||||
CLUTTER_CAIRO_FORMAT_ARGB32,
|
||||
data);
|
||||
|
||||
recorder_draw_cursor (recorder, buffer);
|
||||
|
@ -101,6 +101,32 @@ shell_tp_client_init (ShellTpClient *self)
|
||||
/* Approver */
|
||||
tp_base_client_add_approver_filter (TP_BASE_CLIENT (self), filter);
|
||||
|
||||
/* Approve room invitations. We don't handle or observe room channels so
|
||||
* just register this filter for the approver. */
|
||||
tp_base_client_take_approver_filter (TP_BASE_CLIENT (self), tp_asv_new (
|
||||
TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
|
||||
TP_IFACE_CHANNEL_TYPE_TEXT,
|
||||
TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT,
|
||||
TP_HANDLE_TYPE_ROOM,
|
||||
NULL));
|
||||
|
||||
/* Approve calls (StreameMedia and Call.DRAFT). We let Empathy handle the
|
||||
* call itself. */
|
||||
tp_base_client_take_approver_filter (TP_BASE_CLIENT (self),
|
||||
tp_asv_new (
|
||||
TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
|
||||
TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA,
|
||||
TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT,
|
||||
NULL));
|
||||
|
||||
/* FIXME: use TP_IFACE_CHANNEL_TYPE_CALL once API is undrafted (fdo #24936) */
|
||||
tp_base_client_take_approver_filter (TP_BASE_CLIENT (self),
|
||||
tp_asv_new (
|
||||
TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
|
||||
"org.freedesktop.Telepathy.Channel.Type.Call.DRAFT",
|
||||
TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT,
|
||||
NULL));
|
||||
|
||||
/* Handler */
|
||||
tp_base_client_add_handler_filter (TP_BASE_CLIENT (self), filter);
|
||||
|
||||
@ -371,3 +397,15 @@ shell_get_contact_events (TplLogManager *log_manager,
|
||||
NULL, NULL,
|
||||
callback, NULL);
|
||||
}
|
||||
|
||||
/* gjs doesn't allow us to craft a GError so we need a C wrapper */
|
||||
void
|
||||
shell_decline_dispatch_op (TpAddDispatchOperationContext *context,
|
||||
const gchar *message)
|
||||
{
|
||||
GError *error = g_error_new_literal (TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
|
||||
message);
|
||||
|
||||
tp_add_dispatch_operation_context_fail (context, error);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
@ -111,5 +111,8 @@ void shell_get_contact_events (TplLogManager *log_manager,
|
||||
guint num_events,
|
||||
GAsyncReadyCallback callback);
|
||||
|
||||
void shell_decline_dispatch_op (TpAddDispatchOperationContext *context,
|
||||
const gchar *message);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* __SHELL_TP_CLIENT_H__ */
|
||||
|
@ -560,6 +560,29 @@ shell_get_event_state (ClutterEvent *event)
|
||||
return state & CLUTTER_MODIFIER_MASK;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_write_soup_message_to_stream:
|
||||
* @stream: a #GOutputStream
|
||||
* @message: a #SoupMessage
|
||||
* @error: location to store GError
|
||||
*
|
||||
* Write a string to a GOutputStream as binary data. This is a
|
||||
* workaround for the lack of proper binary strings in GJS.
|
||||
*/
|
||||
void
|
||||
shell_write_soup_message_to_stream (GOutputStream *stream,
|
||||
SoupMessage *message,
|
||||
GError **error)
|
||||
{
|
||||
SoupMessageBody *body;
|
||||
|
||||
body = message->response_body;
|
||||
|
||||
g_output_stream_write_all (stream,
|
||||
body->data, body->length,
|
||||
NULL, NULL, error);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_write_string_to_stream:
|
||||
* @stream: a #GOutputStream
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <clutter/clutter.h>
|
||||
#include <libsoup/soup.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@ -25,6 +26,10 @@ char *shell_util_format_date (const char *format,
|
||||
ClutterModifierType
|
||||
shell_get_event_state (ClutterEvent *event);
|
||||
|
||||
void shell_write_soup_message_to_stream (GOutputStream *stream,
|
||||
SoupMessage *message,
|
||||
GError **error);
|
||||
|
||||
gboolean shell_write_string_to_stream (GOutputStream *stream,
|
||||
const char *str,
|
||||
GError **error);
|
||||
|
@ -232,11 +232,7 @@ xfixes_cursor_reset_image (ShellXFixesCursor *xfixes_cursor)
|
||||
sprite = cogl_texture_new_from_data (cursor_image->width,
|
||||
cursor_image->height,
|
||||
COGL_TEXTURE_NONE,
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
COGL_PIXEL_FORMAT_BGRA_8888_PRE,
|
||||
#else
|
||||
COGL_PIXEL_FORMAT_ARGB_8888_PRE,
|
||||
#endif
|
||||
CLUTTER_CAIRO_FORMAT_ARGB32,
|
||||
COGL_PIXEL_FORMAT_ANY,
|
||||
cursor_image->width * 4, /* stride */
|
||||
cursor_data);
|
||||
|
@ -36,15 +36,6 @@
|
||||
|
||||
#include <cairo.h>
|
||||
|
||||
/* Cairo stores the data in native byte order as ARGB but Cogl's pixel
|
||||
formats specify the actual byte order. Therefore we need to use a
|
||||
different format depending on the architecture */
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
#define PIXEL_FORMAT COGL_PIXEL_FORMAT_BGRA_8888_PRE
|
||||
#else
|
||||
#define PIXEL_FORMAT COGL_PIXEL_FORMAT_ARGB_8888_PRE
|
||||
#endif
|
||||
|
||||
G_DEFINE_TYPE(StDrawingArea, st_drawing_area, ST_TYPE_WIDGET);
|
||||
|
||||
struct _StDrawingAreaPrivate {
|
||||
@ -122,7 +113,7 @@ st_drawing_area_paint (ClutterActor *self)
|
||||
{
|
||||
priv->texture = cogl_texture_new_with_size (width, height,
|
||||
COGL_TEXTURE_NONE,
|
||||
PIXEL_FORMAT);
|
||||
CLUTTER_CAIRO_FORMAT_ARGB32);
|
||||
priv->needs_repaint = TRUE;
|
||||
}
|
||||
|
||||
@ -142,7 +133,7 @@ st_drawing_area_paint (ClutterActor *self)
|
||||
priv->context = NULL;
|
||||
|
||||
cogl_texture_set_region (priv->texture, 0, 0, 0, 0, width, height, width, height,
|
||||
PIXEL_FORMAT,
|
||||
CLUTTER_CAIRO_FORMAT_ARGB32,
|
||||
cairo_image_surface_get_stride (surface),
|
||||
cairo_image_surface_get_data (surface));
|
||||
|
||||
|
@ -200,15 +200,18 @@ st_entry_style_changed (StWidget *self)
|
||||
st_theme_node_get_foreground_color (theme_node, &color);
|
||||
clutter_text_set_color (CLUTTER_TEXT (priv->entry), &color);
|
||||
|
||||
if (st_theme_node_lookup_length (theme_node, "caret-size", FALSE, &size))
|
||||
if (st_theme_node_lookup_length (theme_node, "caret-size", TRUE, &size))
|
||||
clutter_text_set_cursor_size (CLUTTER_TEXT (priv->entry), (int)(.5 + size));
|
||||
|
||||
if (st_theme_node_lookup_color (theme_node, "caret-color", FALSE, &color))
|
||||
if (st_theme_node_lookup_color (theme_node, "caret-color", TRUE, &color))
|
||||
clutter_text_set_cursor_color (CLUTTER_TEXT (priv->entry), &color);
|
||||
|
||||
if (st_theme_node_lookup_color (theme_node, "selection-background-color", FALSE, &color))
|
||||
if (st_theme_node_lookup_color (theme_node, "selection-background-color", TRUE, &color))
|
||||
clutter_text_set_selection_color (CLUTTER_TEXT (priv->entry), &color);
|
||||
|
||||
if (st_theme_node_lookup_color (theme_node, "selected-color", TRUE, &color))
|
||||
clutter_text_set_selected_text_color (CLUTTER_TEXT (priv->entry), &color);
|
||||
|
||||
font = st_theme_node_get_font (theme_node);
|
||||
font_string = pango_font_description_to_string (font);
|
||||
clutter_text_set_font_name (CLUTTER_TEXT (priv->entry), font_string);
|
||||
|
@ -167,11 +167,7 @@ create_corner_material (StCornerSpec *corner)
|
||||
|
||||
texture = cogl_texture_new_from_data (size, size,
|
||||
COGL_TEXTURE_NONE,
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
COGL_PIXEL_FORMAT_BGRA_8888_PRE,
|
||||
#else
|
||||
COGL_PIXEL_FORMAT_ARGB_8888_PRE,
|
||||
#endif
|
||||
CLUTTER_CAIRO_FORMAT_ARGB32,
|
||||
COGL_PIXEL_FORMAT_ANY,
|
||||
rowstride,
|
||||
data);
|
||||
@ -257,6 +253,57 @@ over (const ClutterColor *source,
|
||||
unpremultiply (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* st_theme_node_reduce_border_radius:
|
||||
* @node: a #StThemeNode
|
||||
* @corners: (array length=4) (out): reduced corners
|
||||
*
|
||||
* Implements the corner overlap algorithm mentioned at
|
||||
* http://www.w3.org/TR/css3-background/#corner-overlap
|
||||
*/
|
||||
static void
|
||||
st_theme_node_reduce_border_radius (StThemeNode *node,
|
||||
guint *corners)
|
||||
{
|
||||
gfloat scale;
|
||||
guint sum;
|
||||
|
||||
scale = 1.0;
|
||||
|
||||
/* top */
|
||||
sum = node->border_radius[ST_CORNER_TOPLEFT]
|
||||
+ node->border_radius[ST_CORNER_TOPRIGHT];
|
||||
|
||||
if (sum > 0)
|
||||
scale = MIN (node->alloc_width / sum, scale);
|
||||
|
||||
/* right */
|
||||
sum = node->border_radius[ST_CORNER_TOPRIGHT]
|
||||
+ node->border_radius[ST_CORNER_BOTTOMRIGHT];
|
||||
|
||||
if (sum > 0)
|
||||
scale = MIN (node->alloc_height / sum, scale);
|
||||
|
||||
/* bottom */
|
||||
sum = node->border_radius[ST_CORNER_BOTTOMLEFT]
|
||||
+ node->border_radius[ST_CORNER_BOTTOMRIGHT];
|
||||
|
||||
if (sum > 0)
|
||||
scale = MIN (node->alloc_width / sum, scale);
|
||||
|
||||
/* left */
|
||||
sum = node->border_radius[ST_CORNER_BOTTOMLEFT]
|
||||
+ node->border_radius[ST_CORNER_TOPLEFT];
|
||||
|
||||
if (sum > 0)
|
||||
scale = MIN (node->alloc_height / sum, scale);
|
||||
|
||||
corners[ST_CORNER_TOPLEFT] = node->border_radius[ST_CORNER_TOPLEFT] * scale;
|
||||
corners[ST_CORNER_TOPRIGHT] = node->border_radius[ST_CORNER_TOPRIGHT] * scale;
|
||||
corners[ST_CORNER_BOTTOMLEFT] = node->border_radius[ST_CORNER_BOTTOMLEFT] * scale;
|
||||
corners[ST_CORNER_BOTTOMRIGHT] = node->border_radius[ST_CORNER_BOTTOMRIGHT] * scale;
|
||||
}
|
||||
|
||||
static void
|
||||
st_theme_node_get_corner_border_widths (StThemeNode *node,
|
||||
StCorner corner_id,
|
||||
@ -301,13 +348,15 @@ st_theme_node_lookup_corner (StThemeNode *node,
|
||||
StTextureCache *cache;
|
||||
StCornerSpec corner;
|
||||
LoadCornerData data;
|
||||
guint radius[4];
|
||||
|
||||
if (node->border_radius[corner_id] == 0)
|
||||
return COGL_INVALID_HANDLE;
|
||||
|
||||
cache = st_texture_cache_get_default ();
|
||||
|
||||
corner.radius = node->border_radius[corner_id];
|
||||
st_theme_node_reduce_border_radius (node, radius);
|
||||
corner.radius = radius[corner_id];
|
||||
corner.color = node->background_color;
|
||||
st_theme_node_get_corner_border_widths (node, corner_id,
|
||||
&corner.border_width_1,
|
||||
@ -877,7 +926,8 @@ st_theme_node_prerender_background (StThemeNode *node)
|
||||
{
|
||||
StBorderImage *border_image;
|
||||
CoglHandle texture;
|
||||
int radius[4], i;
|
||||
guint radius[4];
|
||||
int i;
|
||||
cairo_t *cr;
|
||||
cairo_surface_t *surface;
|
||||
StShadow *shadow_spec;
|
||||
@ -944,12 +994,10 @@ st_theme_node_prerender_background (StThemeNode *node)
|
||||
/* TODO - support non-uniform border colors */
|
||||
get_arbitrary_border_color (node, &border_color);
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
border_width[i] = st_theme_node_get_border_width (node, i);
|
||||
st_theme_node_reduce_border_radius (node, radius);
|
||||
|
||||
radius[i] = st_theme_node_get_border_radius (node, i);
|
||||
}
|
||||
for (i = 0; i < 4; i++)
|
||||
border_width[i] = st_theme_node_get_border_width (node, i);
|
||||
|
||||
/* Note we don't support translucent background images on top
|
||||
* of gradients. It's strictly either/or.
|
||||
@ -1198,14 +1246,7 @@ st_theme_node_prerender_background (StThemeNode *node)
|
||||
texture = cogl_texture_new_from_data (paint_box.x2 - paint_box.x1,
|
||||
paint_box.y2 - paint_box.y1,
|
||||
COGL_TEXTURE_NONE,
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
COGL_PIXEL_FORMAT_BGRA_8888_PRE,
|
||||
#elif G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
COGL_PIXEL_FORMAT_ARGB_8888_PRE,
|
||||
#else
|
||||
COGL_PIXEL_FORMAT_ANY,
|
||||
#error unknown endianness type
|
||||
#endif
|
||||
CLUTTER_CAIRO_FORMAT_ARGB32,
|
||||
COGL_PIXEL_FORMAT_ANY,
|
||||
rowstride,
|
||||
data);
|
||||
@ -1278,6 +1319,7 @@ st_theme_node_render_resources (StThemeNode *node,
|
||||
gboolean has_border;
|
||||
gboolean has_border_radius;
|
||||
gboolean has_inset_box_shadow;
|
||||
gboolean has_large_corners;
|
||||
StShadow *box_shadow_spec;
|
||||
StShadow *background_image_shadow_spec;
|
||||
const char *background_image;
|
||||
@ -1315,6 +1357,27 @@ st_theme_node_render_resources (StThemeNode *node,
|
||||
else
|
||||
has_border_radius = FALSE;
|
||||
|
||||
/* The cogl code pads each corner to the maximum border radius,
|
||||
* which results in overlapping corner areas if the radius
|
||||
* exceeds the actor's halfsize, causing rendering errors.
|
||||
* Fall back to cairo in these cases. */
|
||||
has_large_corners = FALSE;
|
||||
|
||||
if (has_border_radius) {
|
||||
guint border_radius[4];
|
||||
int corner;
|
||||
|
||||
st_theme_node_reduce_border_radius (node, border_radius);
|
||||
|
||||
for (corner = 0; corner < 4; corner ++) {
|
||||
if (border_radius[corner] * 2 > height ||
|
||||
border_radius[corner] * 2 > width) {
|
||||
has_large_corners = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Load referenced images from disk and draw anything we need with cairo now */
|
||||
background_image = st_theme_node_get_background_image (node);
|
||||
border_image = st_theme_node_get_border_image (node);
|
||||
@ -1335,7 +1398,8 @@ st_theme_node_render_resources (StThemeNode *node,
|
||||
|
||||
/* Use cairo to prerender the node if there is a gradient, or
|
||||
* background image with borders and/or rounded corners,
|
||||
* since we can't do those things easily with cogl.
|
||||
* or large corners, since we can't do those things
|
||||
* easily with cogl.
|
||||
*
|
||||
* FIXME: if we could figure out ahead of time that a
|
||||
* background image won't overlap with the node borders,
|
||||
@ -1343,7 +1407,8 @@ st_theme_node_render_resources (StThemeNode *node,
|
||||
*/
|
||||
if ((node->background_gradient_type != ST_GRADIENT_NONE)
|
||||
|| (has_inset_box_shadow && (has_border || node->background_color.alpha > 0))
|
||||
|| (background_image && (has_border || has_border_radius)))
|
||||
|| (background_image && (has_border || has_border_radius))
|
||||
|| has_large_corners)
|
||||
node->prerendered_texture = st_theme_node_prerender_background (node);
|
||||
|
||||
if (node->prerendered_texture)
|
||||
@ -1457,6 +1522,7 @@ st_theme_node_paint_borders (StThemeNode *node,
|
||||
{
|
||||
float width, height;
|
||||
int border_width[4];
|
||||
guint border_radius[4];
|
||||
int max_border_radius = 0;
|
||||
int max_width_radius[4];
|
||||
int corner_id, side_id;
|
||||
@ -1472,6 +1538,8 @@ st_theme_node_paint_borders (StThemeNode *node,
|
||||
for (side_id = 0; side_id < 4; side_id++)
|
||||
border_width[side_id] = st_theme_node_get_border_width(node, side_id);
|
||||
|
||||
st_theme_node_reduce_border_radius (node, border_radius);
|
||||
|
||||
for (corner_id = 0; corner_id < 4; corner_id++)
|
||||
{
|
||||
guint border_width_1, border_width_2;
|
||||
@ -1479,10 +1547,10 @@ st_theme_node_paint_borders (StThemeNode *node,
|
||||
st_theme_node_get_corner_border_widths (node, corner_id,
|
||||
&border_width_1, &border_width_2);
|
||||
|
||||
if (node->border_radius[corner_id] > max_border_radius)
|
||||
max_border_radius = node->border_radius[corner_id];
|
||||
if (border_radius[corner_id] > max_border_radius)
|
||||
max_border_radius = border_radius[corner_id];
|
||||
max_width_radius[corner_id] = MAX(MAX(border_width_1, border_width_2),
|
||||
node->border_radius[corner_id]);
|
||||
border_radius[corner_id]);
|
||||
}
|
||||
|
||||
/* borders */
|
||||
@ -1506,8 +1574,8 @@ st_theme_node_paint_borders (StThemeNode *node,
|
||||
alpha);
|
||||
|
||||
/* NORTH */
|
||||
skip_corner_1 = node->border_radius[ST_CORNER_TOPLEFT] > 0;
|
||||
skip_corner_2 = node->border_radius[ST_CORNER_TOPRIGHT] > 0;
|
||||
skip_corner_1 = border_radius[ST_CORNER_TOPLEFT] > 0;
|
||||
skip_corner_2 = border_radius[ST_CORNER_TOPRIGHT] > 0;
|
||||
|
||||
x1 = skip_corner_1 ? max_width_radius[ST_CORNER_TOPLEFT] : 0;
|
||||
y1 = 0;
|
||||
@ -1516,8 +1584,8 @@ st_theme_node_paint_borders (StThemeNode *node,
|
||||
cogl_rectangle (x1, y1, x2, y2);
|
||||
|
||||
/* EAST */
|
||||
skip_corner_1 = node->border_radius[ST_CORNER_TOPRIGHT] > 0;
|
||||
skip_corner_2 = node->border_radius[ST_CORNER_BOTTOMRIGHT] > 0;
|
||||
skip_corner_1 = border_radius[ST_CORNER_TOPRIGHT] > 0;
|
||||
skip_corner_2 = border_radius[ST_CORNER_BOTTOMRIGHT] > 0;
|
||||
|
||||
x1 = width - border_width[ST_SIDE_RIGHT];
|
||||
y1 = skip_corner_1 ? max_width_radius[ST_CORNER_TOPRIGHT]
|
||||
@ -1528,8 +1596,8 @@ st_theme_node_paint_borders (StThemeNode *node,
|
||||
cogl_rectangle (x1, y1, x2, y2);
|
||||
|
||||
/* SOUTH */
|
||||
skip_corner_1 = node->border_radius[ST_CORNER_BOTTOMLEFT] > 0;
|
||||
skip_corner_2 = node->border_radius[ST_CORNER_BOTTOMRIGHT] > 0;
|
||||
skip_corner_1 = border_radius[ST_CORNER_BOTTOMLEFT] > 0;
|
||||
skip_corner_2 = border_radius[ST_CORNER_BOTTOMRIGHT] > 0;
|
||||
|
||||
x1 = skip_corner_1 ? max_width_radius[ST_CORNER_BOTTOMLEFT] : 0;
|
||||
y1 = height - border_width[ST_SIDE_BOTTOM];
|
||||
@ -1539,8 +1607,8 @@ st_theme_node_paint_borders (StThemeNode *node,
|
||||
cogl_rectangle (x1, y1, x2, y2);
|
||||
|
||||
/* WEST */
|
||||
skip_corner_1 = node->border_radius[ST_CORNER_TOPLEFT] > 0;
|
||||
skip_corner_2 = node->border_radius[ST_CORNER_BOTTOMLEFT] > 0;
|
||||
skip_corner_1 = border_radius[ST_CORNER_TOPLEFT] > 0;
|
||||
skip_corner_2 = border_radius[ST_CORNER_BOTTOMLEFT] > 0;
|
||||
|
||||
x1 = 0;
|
||||
y1 = skip_corner_1 ? max_width_radius[ST_CORNER_TOPLEFT]
|
||||
@ -1610,32 +1678,32 @@ st_theme_node_paint_borders (StThemeNode *node,
|
||||
int n_rects;
|
||||
|
||||
/* corner texture does not need padding */
|
||||
if (max_border_radius == node->border_radius[corner_id])
|
||||
if (max_border_radius == border_radius[corner_id])
|
||||
continue;
|
||||
|
||||
n_rects = node->border_radius[corner_id] == 0 ? 1 : 2;
|
||||
n_rects = border_radius[corner_id] == 0 ? 1 : 2;
|
||||
|
||||
switch (corner_id)
|
||||
{
|
||||
case ST_CORNER_TOPLEFT:
|
||||
verts[0] = border_width[ST_SIDE_LEFT];
|
||||
verts[1] = MAX(node->border_radius[corner_id],
|
||||
verts[1] = MAX(border_radius[corner_id],
|
||||
border_width[ST_SIDE_TOP]);
|
||||
verts[2] = max_border_radius;
|
||||
verts[3] = max_border_radius;
|
||||
if (n_rects == 2)
|
||||
{
|
||||
verts[4] = MAX(node->border_radius[corner_id],
|
||||
verts[4] = MAX(border_radius[corner_id],
|
||||
border_width[ST_SIDE_LEFT]);
|
||||
verts[5] = border_width[ST_SIDE_TOP];
|
||||
verts[6] = max_border_radius;
|
||||
verts[7] = MAX(node->border_radius[corner_id],
|
||||
verts[7] = MAX(border_radius[corner_id],
|
||||
border_width[ST_SIDE_TOP]);
|
||||
}
|
||||
break;
|
||||
case ST_CORNER_TOPRIGHT:
|
||||
verts[0] = width - max_border_radius;
|
||||
verts[1] = MAX(node->border_radius[corner_id],
|
||||
verts[1] = MAX(border_radius[corner_id],
|
||||
border_width[ST_SIDE_TOP]);
|
||||
verts[2] = width - border_width[ST_SIDE_RIGHT];
|
||||
verts[3] = max_border_radius;
|
||||
@ -1643,9 +1711,9 @@ st_theme_node_paint_borders (StThemeNode *node,
|
||||
{
|
||||
verts[4] = width - max_border_radius;
|
||||
verts[5] = border_width[ST_SIDE_TOP];
|
||||
verts[6] = width - MAX(node->border_radius[corner_id],
|
||||
verts[6] = width - MAX(border_radius[corner_id],
|
||||
border_width[ST_SIDE_RIGHT]);
|
||||
verts[7] = MAX(node->border_radius[corner_id],
|
||||
verts[7] = MAX(border_radius[corner_id],
|
||||
border_width[ST_SIDE_TOP]);
|
||||
}
|
||||
break;
|
||||
@ -1653,14 +1721,14 @@ st_theme_node_paint_borders (StThemeNode *node,
|
||||
verts[0] = width - max_border_radius;
|
||||
verts[1] = height - max_border_radius;
|
||||
verts[2] = width - border_width[ST_SIDE_RIGHT];
|
||||
verts[3] = height - MAX(node->border_radius[corner_id],
|
||||
verts[3] = height - MAX(border_radius[corner_id],
|
||||
border_width[ST_SIDE_BOTTOM]);
|
||||
if (n_rects == 2)
|
||||
{
|
||||
verts[4] = width - max_border_radius;
|
||||
verts[5] = height - MAX(node->border_radius[corner_id],
|
||||
verts[5] = height - MAX(border_radius[corner_id],
|
||||
border_width[ST_SIDE_BOTTOM]);
|
||||
verts[6] = width - MAX(node->border_radius[corner_id],
|
||||
verts[6] = width - MAX(border_radius[corner_id],
|
||||
border_width[ST_SIDE_RIGHT]);
|
||||
verts[7] = height - border_width[ST_SIDE_BOTTOM];
|
||||
}
|
||||
@ -1669,13 +1737,13 @@ st_theme_node_paint_borders (StThemeNode *node,
|
||||
verts[0] = border_width[ST_SIDE_LEFT];
|
||||
verts[1] = height - max_border_radius;
|
||||
verts[2] = max_border_radius;
|
||||
verts[3] = height - MAX(node->border_radius[corner_id],
|
||||
verts[3] = height - MAX(border_radius[corner_id],
|
||||
border_width[ST_SIDE_BOTTOM]);
|
||||
if (n_rects == 2)
|
||||
{
|
||||
verts[4] = MAX(node->border_radius[corner_id],
|
||||
verts[4] = MAX(border_radius[corner_id],
|
||||
border_width[ST_SIDE_LEFT]);
|
||||
verts[5] = height - MAX(node->border_radius[corner_id],
|
||||
verts[5] = height - MAX(border_radius[corner_id],
|
||||
border_width[ST_SIDE_BOTTOM]);
|
||||
verts[6] = max_border_radius;
|
||||
verts[7] = height - border_width[ST_SIDE_BOTTOM];
|
||||
|
@ -18,7 +18,8 @@ TEST_JS = \
|
||||
testcommon/border-image.png \
|
||||
testcommon/face-plain.png \
|
||||
testcommon/ui.js \
|
||||
unit/format.js
|
||||
unit/format.js \
|
||||
unit/markup.js
|
||||
EXTRA_DIST += $(TEST_JS)
|
||||
|
||||
TEST_MISC = \
|
||||
@ -28,6 +29,7 @@ EXTRA_DIST += $(TEST_MISC)
|
||||
run-test.sh: run-test.sh.in
|
||||
$(AM_V_GEN) sed \
|
||||
-e "s|@MUTTER_TYPELIB_DIR[@]|$(MUTTER_TYPELIB_DIR)|" \
|
||||
-e "s|@JHBUILD_TYPELIBDIR[@]|$(JHBUILD_TYPELIBDIR)|" \
|
||||
-e "s|@srcdir[@]|$(srcdir)|" \
|
||||
$< > $@ && chmod a+x $@
|
||||
|
||||
|
@ -51,6 +51,13 @@ addTestCase(" 5px 10px 15px 0px", true);
|
||||
addTestCase("10px 15px 0px 5px", true);
|
||||
addTestCase("15px 0px 5px 10px", true);
|
||||
|
||||
// border-radius reduction
|
||||
// these should all take the cairo fallback,
|
||||
// so don't bother testing w/ or w/out gradients.
|
||||
addTestCase("200px 200px 200px 200px", false);
|
||||
addTestCase("200px 200px 0px 200px", false);
|
||||
addTestCase("999px 0px 999px 0px", false);
|
||||
|
||||
stage.show();
|
||||
Clutter.main();
|
||||
stage.destroy();
|
||||
|
@ -30,7 +30,7 @@ builddir=`cd $builddir && pwd`
|
||||
srcdir=$builddir/@srcdir@
|
||||
srcdir=`cd $srcdir && pwd`
|
||||
|
||||
GI_TYPELIB_PATH="@MUTTER_TYPELIB_DIR@:$builddir/../src"
|
||||
GI_TYPELIB_PATH="$GI_TYPELIB_PATH${GI_TYPELIB_PATH:+:}@MUTTER_TYPELIB_DIR@:@JHBUILD_TYPELIBDIR@:$builddir/../src"
|
||||
GJS_PATH="$srcdir:$srcdir/../js"
|
||||
GJS_DEBUG_OUTPUT=stderr
|
||||
$verbose || GJS_DEBUG_TOPICS="JS ERROR;JS LOG"
|
||||
|
142
tests/unit/markup.js
Normal file
142
tests/unit/markup.js
Normal file
@ -0,0 +1,142 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
// Test cases for MessageTray markup parsing
|
||||
|
||||
const JsUnit = imports.jsUnit;
|
||||
const Pango = imports.gi.Pango;
|
||||
|
||||
const Environment = imports.ui.environment;
|
||||
Environment.init();
|
||||
|
||||
const MessageTray = imports.ui.messageTray;
|
||||
|
||||
// Assert that @input, assumed to be markup, gets "fixed" to @output,
|
||||
// which is valid markup. If @output is null, @input is expected to
|
||||
// convert to itself
|
||||
function assertConverts(input, output) {
|
||||
if (!output)
|
||||
output = input;
|
||||
let fixed = MessageTray._fixMarkup(input, true);
|
||||
JsUnit.assertEquals(output, fixed);
|
||||
|
||||
let parsed = false;
|
||||
try {
|
||||
Pango.parse_markup(fixed, -1, '');
|
||||
parsed = true;
|
||||
} catch (e) {}
|
||||
JsUnit.assertEquals(true, parsed);
|
||||
}
|
||||
|
||||
// Assert that @input, assumed to be plain text, gets escaped to @output,
|
||||
// which is valid markup.
|
||||
function assertEscapes(input, output) {
|
||||
let fixed = MessageTray._fixMarkup(input, false);
|
||||
JsUnit.assertEquals(output, fixed);
|
||||
|
||||
let parsed = false;
|
||||
try {
|
||||
Pango.parse_markup(fixed, -1, '');
|
||||
parsed = true;
|
||||
} catch (e) {}
|
||||
JsUnit.assertEquals(true, parsed);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// CORRECT MARKUP
|
||||
|
||||
assertConverts('foo');
|
||||
assertEscapes('foo', 'foo');
|
||||
|
||||
assertConverts('<b>foo</b>');
|
||||
assertEscapes('<b>foo</b>', '<b>foo</b>');
|
||||
|
||||
assertConverts('something <i>foo</i>');
|
||||
assertEscapes('something <i>foo</i>', 'something <i>foo</i>');
|
||||
|
||||
assertConverts('<u>foo</u> something');
|
||||
assertEscapes('<u>foo</u> something', '<u>foo</u> something');
|
||||
|
||||
assertConverts('<b>bold</b> <i>italic <u>and underlined</u></i>');
|
||||
assertEscapes('<b>bold</b> <i>italic <u>and underlined</u></i>', '<b>bold</b> <i>italic <u>and underlined</u></i>');
|
||||
|
||||
assertConverts('this & that');
|
||||
assertEscapes('this & that', 'this &amp; that');
|
||||
|
||||
assertConverts('this < that');
|
||||
assertEscapes('this < that', 'this &lt; that');
|
||||
|
||||
assertConverts('this < that > the other');
|
||||
assertEscapes('this < that > the other', 'this &lt; that &gt; the other');
|
||||
|
||||
assertConverts('this <<i>that</i>>');
|
||||
assertEscapes('this <<i>that</i>>', 'this &lt;<i>that</i>&gt;');
|
||||
|
||||
assertConverts('<b>this</b> > <i>that</i>');
|
||||
assertEscapes('<b>this</b> > <i>that</i>', '<b>this</b> > <i>that</i>');
|
||||
|
||||
|
||||
|
||||
// PARTIALLY CORRECT MARKUP
|
||||
// correct bits are kept, incorrect bits are escaped
|
||||
|
||||
// unrecognized entity
|
||||
assertConverts('<b>smile</b> ☺!', '<b>smile</b> &#9786;!');
|
||||
assertEscapes('<b>smile</b> ☺!', '<b>smile</b> &#9786;!');
|
||||
|
||||
// stray '&'; this is really a bug, but it's easier to do it this way
|
||||
assertConverts('<b>this</b> & <i>that</i>', '<b>this</b> & <i>that</i>');
|
||||
assertEscapes('<b>this</b> & <i>that</i>', '<b>this</b> & <i>that</i>');
|
||||
|
||||
// likewise with stray '<'
|
||||
assertConverts('this < that', 'this < that');
|
||||
assertEscapes('this < that', 'this < that');
|
||||
|
||||
assertConverts('<b>this</b> < <i>that</i>', '<b>this</b> < <i>that</i>');
|
||||
assertEscapes('<b>this</b> < <i>that</i>', '<b>this</b> < <i>that</i>');
|
||||
|
||||
assertConverts('this < that > the other', 'this < that > the other');
|
||||
assertEscapes('this < that > the other', 'this < that > the other');
|
||||
|
||||
assertConverts('this <<i>that</i>>', 'this <<i>that</i>>');
|
||||
assertEscapes('this <<i>that</i>>', 'this <<i>that</i>>');
|
||||
|
||||
// unknown tags
|
||||
assertConverts('<unknown>tag</unknown>', '<unknown>tag</unknown>');
|
||||
assertEscapes('<unknown>tag</unknown>', '<unknown>tag</unknown>');
|
||||
|
||||
// make sure we check beyond the first letter
|
||||
assertConverts('<bunknown>tag</bunknown>', '<bunknown>tag</bunknown>');
|
||||
assertEscapes('<bunknown>tag</bunknown>', '<bunknown>tag</bunknown>');
|
||||
|
||||
// with mix of good and bad, we keep the good and escape the bad
|
||||
assertConverts('<i>known</i> and <unknown>tag</unknown>', '<i>known</i> and <unknown>tag</unknown>');
|
||||
assertEscapes('<i>known</i> and <unknown>tag</unknown>', '<i>known</i> and <unknown>tag</unknown>');
|
||||
|
||||
|
||||
|
||||
// FULLY INCORRECT MARKUP
|
||||
// (fall back to escaping the whole thing)
|
||||
|
||||
// tags not matched up
|
||||
assertConverts('<b>in<i>com</i>plete', '<b>in<i>com</i>plete');
|
||||
assertEscapes('<b>in<i>com</i>plete', '<b>in<i>com</i>plete');
|
||||
|
||||
assertConverts('in<i>com</i>plete</b>', 'in<i>com</i>plete</b>');
|
||||
assertEscapes('in<i>com</i>plete</b>', 'in<i>com</i>plete</b>');
|
||||
|
||||
// we don't support attributes, and it's too complicated to try
|
||||
// to escape both start and end tags, so we just treat it as bad
|
||||
assertConverts('<b>good</b> and <b style=\'bad\'>bad</b>', '<b>good</b> and <b style='bad'>bad</b>');
|
||||
assertEscapes('<b>good</b> and <b style=\'bad\'>bad</b>', '<b>good</b> and <b style='bad'>bad</b>');
|
||||
|
||||
// this is just syntactically invalid
|
||||
assertConverts('<b>unrecognized</b stuff>', '<b>unrecognized</b stuff>');
|
||||
assertEscapes('<b>unrecognized</b stuff>', '<b>unrecognized</b stuff>');
|
||||
|
||||
// mismatched tags
|
||||
assertConverts('<b>mismatched</i>', '<b>mismatched</i>');
|
||||
assertEscapes('<b>mismatched</i>', '<b>mismatched</i>');
|
||||
|
||||
assertConverts('<b>mismatched/unknown</bunknown>', '<b>mismatched/unknown</bunknown>');
|
||||
assertEscapes('<b>mismatched/unknown</bunknown>', '<b>mismatched/unknown</bunknown>');
|
12
tools/build/gnome-shell-build-setup.sh
Executable file → Normal file
12
tools/build/gnome-shell-build-setup.sh
Executable file → Normal file
@ -59,7 +59,7 @@ fi
|
||||
# Devel packages needed by gnome-shell and its deps:
|
||||
# dbus-glib, expat, GL, gnome-menus, gstreamer, libffi,
|
||||
# libjasper, libjpeg, libpng, libpulse, libtiff, libwnck,
|
||||
# iso-codes, libical, libxml2, ORBit2, pam, python, readline,
|
||||
# iso-codes, libical, libxml2, ORBit2, pam, python, readline, upower,
|
||||
# spidermonkey ({mozilla,firefox,xulrunner}-js), startup-notification,
|
||||
# xdamage, icon-naming-utils, upower, libtool-ltdl, libvorbis,
|
||||
# libgcrypt, libtasn1, libgnome-keyring, libgtop, cups, xcb, WebKit-gtk
|
||||
@ -84,9 +84,15 @@ if test "x$system" = xUbuntu -o "x$system" = xDebian -o "x$system" = xLinuxMint
|
||||
libltdl-dev libvorbis-dev iso-codes libgnome-keyring-dev libusb-1.0-0-dev
|
||||
libupower-glib-dev libcups2-dev libproxy-dev libdb-dev libproxy-dev
|
||||
libsqlite3-dev libgudev-1.0-dev libsane-dev libwebkitgtk-3.0-0
|
||||
libx11-xcb-dev libxcb-event1-dev libxcb-aux0-dev
|
||||
libx11-xcb-dev libupower-glib-dev
|
||||
"
|
||||
|
||||
if apt-cache show libxcb-util0-dev > /dev/null 2> /dev/null; then
|
||||
reqd="$reqd libxcb-util0-dev"
|
||||
else
|
||||
reqd="$reqd libxcb-event1-dev libxcb-aux0-dev"
|
||||
fi
|
||||
|
||||
if apt-cache show autopoint > /dev/null 2> /dev/null; then
|
||||
reqd="$reqd autopoint"
|
||||
fi
|
||||
@ -119,7 +125,7 @@ if test "x$system" = xFedora ; then
|
||||
pulseaudio-libs-devel python-devel pygobject2 readline-devel xulrunner-devel
|
||||
libXdamage-devel libcroco-devel libxml2-devel gstreamer-devel
|
||||
gstreamer-plugins-base gstreamer-plugins-good glx-utils expat-devel
|
||||
startup-notification-devel zenity webkitgtk3-devel
|
||||
startup-notification-devel zenity webkitgtk3-devel upower-devel
|
||||
icon-naming-utils upower-devel libtool-ltdl-devel libvorbis-devel
|
||||
iso-codes-devel libgcrypt-devel libtasn1-devel libtasn1-tools libusb1-devel
|
||||
libgnome-keyring-devel libgtop2-devel cups-devel db4-devel libproxy-devel
|
||||
|
@ -295,19 +295,6 @@
|
||||
</dependencies>
|
||||
</autotools>
|
||||
|
||||
<autotools id="gnome-power-manager">
|
||||
<branch repo="git.gnome.org" module="gnome-power-manager" />
|
||||
<dependencies>
|
||||
<dep package="gtk3"/>
|
||||
<dep package="glib"/>
|
||||
<dep package="gconf"/>
|
||||
<dep package="cairo"/>
|
||||
<dep package="libnotify"/>
|
||||
<dep package="libcanberra"/>
|
||||
<dep package="gnome-control-center"/>
|
||||
</dependencies>
|
||||
</autotools>
|
||||
|
||||
<autotools id="telepathy-glib" autogenargs="--disable-Werror" >
|
||||
<branch repo="git.freedesktop.org" module="telepathy/telepathy-glib" />
|
||||
<dependencies>
|
||||
@ -342,7 +329,7 @@
|
||||
<dep package="gnome-bluetooth"/>
|
||||
<dep package="telepathy-glib"/>
|
||||
<dep package="telepathy-logger"/>
|
||||
<dep package="upower"/>
|
||||
<dep package="libsoup"/>
|
||||
</dependencies>
|
||||
</autotools>
|
||||
|
||||
@ -360,7 +347,6 @@
|
||||
<dep package="librsvg"/>
|
||||
<dep package="gnome-themes-standard"/>
|
||||
<dep package="gnome-shell"/>
|
||||
<dep package="gnome-power-manager"/>
|
||||
</dependencies>
|
||||
</metamodule>
|
||||
|
||||
@ -385,19 +371,6 @@
|
||||
</suggests>
|
||||
</tarball>
|
||||
|
||||
<tarball id="upower" version="0.9.8">
|
||||
<source href="http://upower.freedesktop.org/releases/upower-0.9.8.tar.bz2"
|
||||
hash="sha256:7afaec3cb10ebbc898308c7abd250c27fd58e10379a42e80444d7a4b32f2eb91"
|
||||
size="462754"/>
|
||||
<dependencies>
|
||||
<dep package="polkit"/>
|
||||
</dependencies>
|
||||
<suggests>
|
||||
<dep package="gobject-introspection"/>
|
||||
<dep package="gudev"/>
|
||||
</suggests>
|
||||
</tarball>
|
||||
|
||||
<autotools id="libnotify">
|
||||
<branch repo="git.gnome.org" module="libnotify"/>
|
||||
<dependencies>
|
||||
|
Reference in New Issue
Block a user