Compare commits
93 Commits
Author | SHA1 | Date | |
---|---|---|---|
3d5312e8d2 | |||
bc91b7dcae | |||
4d77eb94ff | |||
1b8d03f945 | |||
de2dcfeb99 | |||
c7196a519f | |||
0d82ce5210 | |||
3ce9ad05b3 | |||
ab75faac74 | |||
9e25e13218 | |||
69e1503c6d | |||
7eaf231e56 | |||
a347a72091 | |||
560daec913 | |||
d9e968d863 | |||
556d5d181e | |||
4e4092f9e8 | |||
fd62aba71c | |||
ef0aa65774 | |||
6b5f9a647a | |||
01c07fbea1 | |||
81929c2a92 | |||
d9ff8e3122 | |||
0c4692ae58 | |||
df56ff4f09 | |||
96cdc9c4eb | |||
3b4ad5cd7d | |||
317c6b77f3 | |||
e5f5a2adaa | |||
594c3174ab | |||
5b7e4bb4a7 | |||
f7c0f826d4 | |||
66af7de6d6 | |||
d1815a36d0 | |||
61de3de909 | |||
36888a34d6 | |||
646435ee3e | |||
cbb8d5b0dc | |||
ebee01b355 | |||
0e3795b2f3 | |||
de73128d47 | |||
281b0a3e63 | |||
c414f9ac9d | |||
77242cfec0 | |||
8ebbba6eb8 | |||
0804cefbee | |||
2404d2935d | |||
e6f5e21b5d | |||
c303c6b5c1 | |||
f58e8f2a35 | |||
ededba0c6d | |||
e112fa92fe | |||
7524210d1f | |||
201dc05416 | |||
2b34978993 | |||
447246da74 | |||
1cf2bb6646 | |||
de1eafb564 | |||
22f0099a5d | |||
300eb87016 | |||
aa38b16368 | |||
266bfdf739 | |||
19ef6b0421 | |||
75570b7995 | |||
3290bfae68 | |||
0805d7a35f | |||
11278a0814 | |||
86de6f5861 | |||
498b023989 | |||
5265884af9 | |||
cdbe0bbf38 | |||
feef35a8ca | |||
3ff51da529 | |||
496e9f7b16 | |||
0b30dc29a5 | |||
15b4d29e70 | |||
9eee4b7687 | |||
196f6c241a | |||
c9296191a8 | |||
c7b4022283 | |||
a7ecc4cdd6 | |||
df5298d59c | |||
b79d17332e | |||
675572a41a | |||
0078fe9349 | |||
dc004f6eb7 | |||
07f1a05ab4 | |||
54292a99af | |||
f5933c8cb8 | |||
6700f86145 | |||
b31d22488e | |||
6382eeb8fd | |||
b07345a55c |
43
NEWS
43
NEWS
@ -1,3 +1,46 @@
|
||||
3.5.3
|
||||
=====
|
||||
* calendar: Adapt to Evolution-Data-Server API changes [Matthew; #677402]
|
||||
* messageTray: Don't show non urgent notifications while in fullscreen
|
||||
[Adel; #677590]
|
||||
* modalDialog: show dialogs on monitor with the mouse pointer [Tim; #642591]
|
||||
* extensionSystem: Prepare for extension updating system [Jasper; #677586]
|
||||
* appDisplay: Don't show apps in NoDisplay categories in the All view
|
||||
[Jasper; #658176]
|
||||
* st: Trigger theme updates on resolution changes [Florian; #677975]
|
||||
* Always enable a11y [Bastien; #678095]
|
||||
* telepathyClient: ignore invalidated channels [Guillaume; #677457]
|
||||
* shell-app: Update app menu if necessary [Florian; #676238]
|
||||
* Enable the Screen Reader menu item [Matthias; #663256]
|
||||
* Disable unredirection when a modal operation is active [Giovanni]
|
||||
* Make folks optional [Colin]
|
||||
* Improve mount-operation support [Cosimo]
|
||||
- Fix exception when showing password entry [#678428]
|
||||
- Close the password entry on operation abort [#673787]
|
||||
- autorun: Don't allow autorun for things we mount on startup [#660595]
|
||||
- Turn passphrase prompt into a dialog [#674962]
|
||||
- Implement org.Gtk.MountOperationHandler [#678516]
|
||||
* Network menu improvements
|
||||
- Sort Wifi networks by strength [Giovanni; #658946]
|
||||
- Prefer wifi/3g over VPN in the panel [Cosimo; #672591]
|
||||
* clock: Switch to using GnomeWallClock [Colin; #657074]
|
||||
* remoteSearch: Allow to reference .desktop file for Title/Icon
|
||||
[Florian; #678816]
|
||||
* Fix memory leaks [Jasper, Pavel; #678079, #678406, #678737]
|
||||
* Misc fixes [Florian, Giovanni, Guillaume, Jasper, Kjartan, Piotr, Rui;
|
||||
#658955, #677497, #678396, #678502]
|
||||
* Misc cleanups [Bastien, Florian, Jasper; #677426, #677515, #678096, #678416]
|
||||
|
||||
Contributors:
|
||||
Matthew Barnes, Giovanni Campagna, Cosimo Cecchi, Matthias Clasen,
|
||||
Guillaume Desmottes, Piotr Drąg, Adel Gadllah, Tim L, Kjartan Maraas,
|
||||
Rui Matos, Florian Müllner, Bastien Nocera, Jasper St. Pierre, Colin Walters
|
||||
|
||||
Translations:
|
||||
Matej Urbančič [sl], Yuri Kozlov [ru], Tom Tryfonidis [el],
|
||||
Kjartan Maraas [nb], Žygimantas Beručka [lt], Luca Ferretti [it],
|
||||
Khaled Hosny [ar], Daniel Mustieles [es], Fran Diéguez [gl], A S Alam [pa]
|
||||
|
||||
3.5.2
|
||||
=====
|
||||
* main: Move 'toggle-recording' binding into the shell [Florian; #674377]
|
||||
|
38
configure.ac
38
configure.ac
@ -1,5 +1,5 @@
|
||||
AC_PREREQ(2.63)
|
||||
AC_INIT([gnome-shell],[3.5.2],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
|
||||
AC_INIT([gnome-shell],[3.5.3],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
|
||||
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_SRCDIR([src/shell-global.c])
|
||||
@ -62,29 +62,47 @@ AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
|
||||
|
||||
CLUTTER_MIN_VERSION=1.9.16
|
||||
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
|
||||
GJS_MIN_VERSION=1.29.18
|
||||
MUTTER_MIN_VERSION=3.5.2
|
||||
GJS_MIN_VERSION=1.33.2
|
||||
MUTTER_MIN_VERSION=3.5.3
|
||||
FOLKS_MIN_VERSION=0.5.2
|
||||
GTK_MIN_VERSION=3.3.9
|
||||
GIO_MIN_VERSION=2.31.6
|
||||
LIBECAL_MIN_VERSION=2.32.0
|
||||
LIBEDATASERVER_MIN_VERSION=1.2.0
|
||||
LIBEDATASERVERUI_MIN_VERSION=2.91.6
|
||||
LIBECAL_MIN_VERSION=3.5.3
|
||||
LIBEDATASERVER_MIN_VERSION=3.5.3
|
||||
LIBEDATASERVERUI_MIN_VERSION=3.5.3
|
||||
TELEPATHY_GLIB_MIN_VERSION=0.17.5
|
||||
TELEPATHY_LOGGER_MIN_VERSION=0.2.4
|
||||
POLKIT_MIN_VERSION=0.100
|
||||
STARTUP_NOTIFICATION_MIN_VERSION=0.11
|
||||
GCR_MIN_VERSION=3.3.90
|
||||
GNOME_DESKTOP_REQUIRED_VERSION=3.5.1
|
||||
GNOME_MENUS_REQUIRED_VERSION=3.5.3
|
||||
|
||||
AC_ARG_WITH(folks,
|
||||
AS_HELP_STRING([--with-folks],
|
||||
[Enable folks support]),
|
||||
[with_folks=$withval], [with_folks=yes])
|
||||
|
||||
if test x${with_folks} = xyes; then
|
||||
FOLKS_REQUIREMENT="folks >= $FOLKS_MIN_VERSION"
|
||||
AC_DEFINE([HAVE_FOLKS], [1], [folks support])
|
||||
AC_SUBST([HAVE_FOLKS],[1])
|
||||
else
|
||||
FOLKS_REQUIREMENT=
|
||||
AC_SUBST([HAVE_FOLKS],[0])
|
||||
fi
|
||||
AM_CONDITIONAL(BUILD_WITH_FOLKS, test x${with_folks} = xyes)
|
||||
|
||||
# Collect more than 20 libraries for a prize!
|
||||
PKG_CHECK_MODULES(GNOME_SHELL, gio-unix-2.0 >= $GIO_MIN_VERSION
|
||||
libxml-2.0
|
||||
gtk+-3.0 >= $GTK_MIN_VERSION
|
||||
folks >= $FOLKS_MIN_VERSION
|
||||
atk-bridge-2.0
|
||||
$FOLKS_REQUIREMENT
|
||||
libmutter >= $MUTTER_MIN_VERSION
|
||||
gjs-internals-1.0 >= $GJS_MIN_VERSION
|
||||
libgnome-menu-3.0 $recorder_modules
|
||||
libgnome-menu-3.0 >= $GNOME_MENUS_REQUIRED_VERSION
|
||||
$recorder_modules
|
||||
gdk-x11-3.0 libsoup-2.4
|
||||
gl
|
||||
clutter-x11-1.0 >= $CLUTTER_MIN_VERSION
|
||||
@ -105,10 +123,6 @@ PKG_CHECK_MODULES(SHELL_HOTPLUG_SNIFFER, gio-2.0 gdk-pixbuf-2.0)
|
||||
|
||||
PKG_CHECK_MODULES(BROWSER_PLUGIN, gio-2.0 >= $GIO_MIN_VERSION json-glib-1.0 >= 0.13.2)
|
||||
|
||||
GJS_VERSION=`$PKG_CONFIG --modversion gjs-internals-1.0`
|
||||
AC_DEFINE_UNQUOTED([GJS_VERSION], ["$GJS_VERSION"], [The version of GJS we're linking to])
|
||||
AC_SUBST([GJS_VERSION], ["$GJS_VERSION"])
|
||||
|
||||
GOBJECT_INTROSPECTION_CHECK([$GOBJECT_INTROSPECTION_MIN_VERSION])
|
||||
|
||||
saved_CFLAGS=$CFLAGS
|
||||
|
@ -53,9 +53,14 @@ dist_theme_DATA = \
|
||||
theme/ws-switch-arrow-up.svg \
|
||||
theme/ws-switch-arrow-down.svg
|
||||
|
||||
gsettings_SCHEMAS = org.gnome.shell.gschema.xml org.gnome.shell.evolution.calendar.gschema.xml
|
||||
gsettings_SCHEMAS = org.gnome.shell.gschema.xml
|
||||
|
||||
@INTLTOOL_XML_NOMERGE_RULE@
|
||||
|
||||
%.gschema.xml.in: %.gschema.xml.in.in Makefile
|
||||
$(AM_V_GEN) sed -e 's|@GETTEXT_PACKAGE[@]|$(GETTEXT_PACKAGE)|g' \
|
||||
$< > $@ || rm $@
|
||||
|
||||
@GSETTINGS_RULES@
|
||||
|
||||
# We need to compile schemas at make time
|
||||
@ -80,13 +85,13 @@ EXTRA_DIST = \
|
||||
$(menu_DATA) \
|
||||
$(shaders_DATA) \
|
||||
$(convert_DATA) \
|
||||
org.gnome.shell.evolution.calendar.gschema.xml.in \
|
||||
org.gnome.shell.gschema.xml.in
|
||||
org.gnome.shell.gschema.xml.in.in
|
||||
|
||||
CLEANFILES = \
|
||||
gnome-shell.desktop.in \
|
||||
gnome-shell-extension-prefs.in \
|
||||
$(desktop_DATA) \
|
||||
$(gsettings_SCHEMAS) \
|
||||
gschemas.compiled
|
||||
|
||||
gschemas.compiled \
|
||||
org.gnome.shell.gschema.valid \
|
||||
org.gnome.shell.gschema.xml.in
|
||||
|
@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- NOTE: This schema is a GNOME 3.4 workaround - it uses the same path
|
||||
as org.gnome.evolution.calendar, but avoids us requiring Evolution
|
||||
be installed. In GNOME 3.6 the selected state will become a flag
|
||||
on the calendar. Because the translations are in Evolution,
|
||||
this is untranslated and in POTFILES.skip.
|
||||
-->
|
||||
<schemalist>
|
||||
<schema path="/org/gnome/evolution/calendar/" id="org.gnome.shell.evolution.calendar" gettext-domain="evolution">
|
||||
<key type="as" name="selected-calendars">
|
||||
<default>[]</default>
|
||||
<summary>List of selected calendars</summary>
|
||||
<description>List of calendars to load</description>
|
||||
</key>
|
||||
<key type="as" name="selected-tasks">
|
||||
<default>[]</default>
|
||||
<summary>List of selected task lists</summary>
|
||||
<description>List of task lists to load</description>
|
||||
</key>
|
||||
</schema>
|
||||
</schemalist>
|
@ -61,7 +61,6 @@ value here is from the TpConnectionPresenceType enumeration.</_summary>
|
||||
<_summary>Internally used to store the last session presence status for the user. The
|
||||
value here is from the GsmPresenceStatus enumeration.</_summary>
|
||||
</key>
|
||||
<child name="clock" schema="org.gnome.shell.clock"/>
|
||||
<child name="calendar" schema="org.gnome.shell.calendar"/>
|
||||
<child name="recorder" schema="org.gnome.shell.recorder"/>
|
||||
<child name="keybindings" schema="org.gnome.shell.keybindings"/>
|
||||
@ -108,24 +107,6 @@ value here is from the GsmPresenceStatus enumeration.</_summary>
|
||||
</key>
|
||||
</schema>
|
||||
|
||||
<schema id="org.gnome.shell.clock" path="/org/gnome/shell/clock/"
|
||||
gettext-domain="@GETTEXT_PACKAGE@">
|
||||
<key name="show-seconds" type="b">
|
||||
<default>false</default>
|
||||
<_summary>Show time with seconds</_summary>
|
||||
<_description>
|
||||
If true, display seconds in time.
|
||||
</_description>
|
||||
</key>
|
||||
<key name="show-date" type="b">
|
||||
<default>false</default>
|
||||
<_summary>Show date in clock</_summary>
|
||||
<_description>
|
||||
If true, display date in the clock, in addition to time.
|
||||
</_description>
|
||||
</key>
|
||||
</schema>
|
||||
|
||||
<schema id="org.gnome.shell.recorder" path="/org/gnome/shell/recorder/"
|
||||
gettext-domain="@GETTEXT_PACKAGE@">
|
||||
<key name="framerate" type="i">
|
@ -436,6 +436,10 @@ StScrollBar StButton#vhandle:hover
|
||||
-boxpointer-gap: 4px
|
||||
}
|
||||
|
||||
#networkMenu {
|
||||
spacing: 4px;
|
||||
}
|
||||
|
||||
/* User Menu */
|
||||
|
||||
#panelUserMenu {
|
||||
|
@ -6,9 +6,8 @@ misc/config.js: misc/config.js.in Makefile
|
||||
[ -d $(@D) ] || $(mkdir_p) $(@D) ; \
|
||||
sed -e "s|[@]PACKAGE_NAME@|$(PACKAGE_NAME)|g" \
|
||||
-e "s|[@]PACKAGE_VERSION@|$(PACKAGE_VERSION)|g" \
|
||||
-e "s|[@]GJS_VERSION@|$(GJS_VERSION)|g" \
|
||||
-e "s|[@]HAVE_FOLKS@|$(HAVE_FOLKS)|g" \
|
||||
-e "s|[@]HAVE_BLUETOOTH@|$(HAVE_BLUETOOTH)|g" \
|
||||
-e "s|[@]SHELL_SYSTEM_CA_FILE@|$(SHELL_SYSTEM_CA_FILE)|g" \
|
||||
-e "s|[@]GETTEXT_PACKAGE@|$(GETTEXT_PACKAGE)|g" \
|
||||
-e "s|[@]datadir@|$(datadir)|g" \
|
||||
-e "s|[@]libexecdir@|$(libexecdir)|g" \
|
||||
@ -52,6 +51,7 @@ nobase_dist_js_DATA = \
|
||||
ui/endSessionDialog.js \
|
||||
ui/environment.js \
|
||||
ui/extensionSystem.js \
|
||||
ui/extensionDownloader.js \
|
||||
ui/flashspot.js \
|
||||
ui/iconGrid.js \
|
||||
ui/keyboard.js \
|
||||
|
@ -202,24 +202,18 @@ const Application = new Lang.Class({
|
||||
},
|
||||
|
||||
_scanExtensions: function() {
|
||||
ExtensionUtils.scanExtensions(Lang.bind(this, function(uuid, dir, type) {
|
||||
if (ExtensionUtils.extensions[uuid] !== undefined)
|
||||
return;
|
||||
|
||||
let extension;
|
||||
try {
|
||||
extension = ExtensionUtils.createExtensionObject(uuid, dir, type);
|
||||
} catch(e) {
|
||||
logError(e, 'Could not create extensions object');
|
||||
return;
|
||||
}
|
||||
|
||||
let iter = this._model.append();
|
||||
this._model.set(iter, [0, 1], [uuid, extension.metadata.name]);
|
||||
this._extensionIters[uuid] = iter;
|
||||
}));
|
||||
let finder = new ExtensionUtils.ExtensionFinder();
|
||||
finder.connect('extension-found', Lang.bind(this, this._extensionFound));
|
||||
finder.scanExtensions();
|
||||
},
|
||||
|
||||
_extensionFound: function(signals, extension) {
|
||||
let iter = this._model.append();
|
||||
this._model.set(iter, [0, 1], [extension.uuid, extension.metadata.name]);
|
||||
this._extensionIters[uuid] = iter;
|
||||
},
|
||||
|
||||
|
||||
_onActivate: function() {
|
||||
this._window.present();
|
||||
},
|
||||
@ -268,7 +262,6 @@ function initEnvironment() {
|
||||
|
||||
function main(argv) {
|
||||
initEnvironment();
|
||||
ExtensionUtils.init();
|
||||
|
||||
Gettext.bindtextdomain(Config.GETTEXT_PACKAGE, Config.LOCALEDIR);
|
||||
Gettext.textdomain(Config.GETTEXT_PACKAGE);
|
||||
|
@ -4,10 +4,10 @@
|
||||
const PACKAGE_NAME = '@PACKAGE_NAME@';
|
||||
/* The version of this package */
|
||||
const PACKAGE_VERSION = '@PACKAGE_VERSION@';
|
||||
/* The version of GJS we're linking to */
|
||||
const GJS_VERSION = '@GJS_VERSION@';
|
||||
/* 1 if gnome-bluetooth is available, 0 otherwise */
|
||||
const HAVE_BLUETOOTH = @HAVE_BLUETOOTH@;
|
||||
/* 1 if folks is available, 0 otherwise */
|
||||
const HAVE_FOLKS = @HAVE_FOLKS@;
|
||||
/* gettext package */
|
||||
const GETTEXT_PACKAGE = '@GETTEXT_PACKAGE@';
|
||||
/* locale dir */
|
||||
|
@ -3,6 +3,9 @@
|
||||
// Common utils for the extension system and the extension
|
||||
// preferences tool
|
||||
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gio = imports.gi.Gio;
|
||||
const ShellJS = imports.gi.ShellJS;
|
||||
@ -14,9 +17,6 @@ const ExtensionType = {
|
||||
PER_USER: 2
|
||||
};
|
||||
|
||||
// GFile for user extensions
|
||||
var userExtensionsDir = null;
|
||||
|
||||
// Maps uuid -> metadata object
|
||||
const extensions = {};
|
||||
|
||||
@ -88,9 +88,6 @@ function isOutOfDate(extension) {
|
||||
if (!versionCheck(extension.metadata['shell-version'], Config.PACKAGE_VERSION))
|
||||
return true;
|
||||
|
||||
if (extension.metadata['js-version'] && !versionCheck(extension.metadata['js-version'], Config.GJS_VERSION))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -155,45 +152,48 @@ function installImporter(extension) {
|
||||
_extension = null;
|
||||
}
|
||||
|
||||
function init() {
|
||||
let userExtensionsPath = GLib.build_filenamev([global.userdatadir, 'extensions']);
|
||||
userExtensionsDir = Gio.file_new_for_path(userExtensionsPath);
|
||||
try {
|
||||
if (!userExtensionsDir.query_exists(null))
|
||||
userExtensionsDir.make_directory_with_parents(null);
|
||||
} catch (e) {
|
||||
logError(e, 'Could not create extensions directory');
|
||||
}
|
||||
}
|
||||
const ExtensionFinder = new Lang.Class({
|
||||
Name: 'ExtensionFinder',
|
||||
|
||||
function scanExtensionsInDirectory(callback, dir, type) {
|
||||
let fileEnum;
|
||||
let file, info;
|
||||
try {
|
||||
fileEnum = dir.enumerate_children('standard::*', Gio.FileQueryInfoFlags.NONE, null);
|
||||
} catch(e) {
|
||||
logError(e, 'Could not enumerate extensions directory');
|
||||
return;
|
||||
}
|
||||
_scanExtensionsInDirectory: function(dir, type) {
|
||||
let fileEnum;
|
||||
let file, info;
|
||||
try {
|
||||
fileEnum = dir.enumerate_children('standard::*', Gio.FileQueryInfoFlags.NONE, null);
|
||||
} catch(e) {
|
||||
logError(e, 'Could not enumerate extensions directory');
|
||||
return;
|
||||
}
|
||||
|
||||
while ((info = fileEnum.next_file(null)) != null) {
|
||||
let fileType = info.get_file_type();
|
||||
if (fileType != Gio.FileType.DIRECTORY)
|
||||
continue;
|
||||
let uuid = info.get_name();
|
||||
let extensionDir = dir.get_child(uuid);
|
||||
callback(uuid, extensionDir, type);
|
||||
}
|
||||
fileEnum.close(null);
|
||||
}
|
||||
while ((info = fileEnum.next_file(null)) != null) {
|
||||
let fileType = info.get_file_type();
|
||||
if (fileType != Gio.FileType.DIRECTORY)
|
||||
continue;
|
||||
let uuid = info.get_name();
|
||||
let extensionDir = dir.get_child(uuid);
|
||||
|
||||
function scanExtensions(callback) {
|
||||
let systemDataDirs = GLib.get_system_data_dirs();
|
||||
scanExtensionsInDirectory(callback, userExtensionsDir, ExtensionType.PER_USER);
|
||||
for (let i = 0; i < systemDataDirs.length; i++) {
|
||||
let dirPath = GLib.build_filenamev([systemDataDirs[i], 'gnome-shell', 'extensions']);
|
||||
let dir = Gio.file_new_for_path(dirPath);
|
||||
if (dir.query_exists(null))
|
||||
scanExtensionsInDirectory(callback, dir, ExtensionType.SYSTEM);
|
||||
let existing = extensions[uuid];
|
||||
if (existing) {
|
||||
log('Extension %s already installed in %s. %s will not be loaded'.format(uuid, existing.path, extensionDir.get_path()));
|
||||
continue;
|
||||
}
|
||||
let extension = createExtensionObject(uuid, extensionDir, type);
|
||||
this.emit('extension-found', extension);
|
||||
}
|
||||
fileEnum.close(null);
|
||||
},
|
||||
|
||||
scanExtensions: function() {
|
||||
let userExtensionsDir = Gio.File.new_for_path(GLib.build_filenamev([global.userdatadir, 'extensions']));
|
||||
this._scanExtensionsInDirectory(userExtensionsDir, ExtensionType.PER_USER);
|
||||
|
||||
let systemDataDirs = GLib.get_system_data_dirs();
|
||||
for (let i = 0; i < systemDataDirs.length; i++) {
|
||||
let dirPath = GLib.build_filenamev([systemDataDirs[i], 'gnome-shell', 'extensions']);
|
||||
let dir = Gio.file_new_for_path(dirPath);
|
||||
if (dir.query_exists(null))
|
||||
this._scanExtensionsInDirectory(dir, ExtensionType.SYSTEM);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(ExtensionFinder.prototype);
|
||||
|
@ -89,18 +89,22 @@ function trySpawn(argv)
|
||||
GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD,
|
||||
null, null);
|
||||
} catch (err) {
|
||||
if (err.code == GLib.SpawnError.G_SPAWN_ERROR_NOENT) {
|
||||
err.message = _("Command not found");
|
||||
} else {
|
||||
/* Rewrite the error in case of ENOENT */
|
||||
if (err.matches(GLib.SpawnError, GLib.SpawnError.NOENT)) {
|
||||
throw new GLib.SpawnError({ code: GLib.SpawnError.NOENT,
|
||||
message: _("Command not found") });
|
||||
} else if (err instanceof GLib.Error) {
|
||||
// The exception from gjs contains an error string like:
|
||||
// Error invoking GLib.spawn_command_line_async: Failed to
|
||||
// execute child process "foo" (No such file or directory)
|
||||
// We are only interested in the part in the parentheses. (And
|
||||
// we can't pattern match the text, since it gets localized.)
|
||||
err.message = err.message.replace(/.*\((.+)\)/, '$1');
|
||||
let message = err.message.replace(/.*\((.+)\)/, '$1');
|
||||
throw new (err.constructor)({ code: err.code,
|
||||
message: message });
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
// Dummy child watch; we don't want to double-fork internally
|
||||
// because then we lose the parent-child relationship, which
|
||||
|
@ -22,6 +22,7 @@ const Search = imports.ui.search;
|
||||
const Tweener = imports.ui.tweener;
|
||||
const Workspace = imports.ui.workspace;
|
||||
const Params = imports.misc.params;
|
||||
const Util = imports.misc.util;
|
||||
|
||||
const MAX_APPLICATION_WORK_MILLIS = 75;
|
||||
const MENU_POPUP_TIMEOUT = 600;
|
||||
@ -36,6 +37,7 @@ const AlphabeticalView = new Lang.Class({
|
||||
|
||||
this._pendingAppLaterId = 0;
|
||||
this._appIcons = {}; // desktop file id
|
||||
this._allApps = [];
|
||||
|
||||
let box = new St.BoxLayout({ vertical: true });
|
||||
box.add(this._grid.actor, { y_align: St.Align.START, expand: true });
|
||||
@ -60,16 +62,22 @@ const AlphabeticalView = new Lang.Class({
|
||||
}));
|
||||
},
|
||||
|
||||
_removeAll: function() {
|
||||
removeAll: function() {
|
||||
this._grid.removeAll();
|
||||
this._appIcons = {};
|
||||
this._allApps = [];
|
||||
},
|
||||
|
||||
_addApp: function(app) {
|
||||
addApp: function(app) {
|
||||
var id = app.get_id();
|
||||
let appIcon = new AppWellIcon(app);
|
||||
if (this._appIcons[id] !== undefined)
|
||||
return;
|
||||
|
||||
this._grid.addItem(appIcon.actor);
|
||||
let appIcon = new AppWellIcon(app);
|
||||
let pos = Util.insertSorted(this._allApps, app, function(a, b) {
|
||||
return a.compare_by_name(b);
|
||||
});
|
||||
this._grid.addItem(appIcon.actor, pos);
|
||||
appIcon.actor.connect('key-focus-in', Lang.bind(this, this._ensureIconVisible));
|
||||
|
||||
this._appIcons[id] = appIcon;
|
||||
@ -120,14 +128,6 @@ const AlphabeticalView = new Lang.Class({
|
||||
icon.actor.visible = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
setAppList: function(apps) {
|
||||
this._removeAll();
|
||||
for (var i = 0; i < apps.length; i++) {
|
||||
var app = apps[i];
|
||||
this._addApp(app);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -147,7 +147,6 @@ const ViewByCategories = new Lang.Class({
|
||||
// (used only before the actor is mapped the first time)
|
||||
this._currentCategory = -2;
|
||||
this._categories = [];
|
||||
this._apps = null;
|
||||
|
||||
this._categoryBox = new St.BoxLayout({ vertical: true,
|
||||
reactive: true,
|
||||
@ -204,16 +203,19 @@ const ViewByCategories = new Lang.Class({
|
||||
if (nextType == GMenu.TreeItemType.ENTRY) {
|
||||
var entry = iter.get_entry();
|
||||
var app = this._appSystem.lookup_app_by_tree_entry(entry);
|
||||
if (!entry.get_app_info().get_nodisplay())
|
||||
if (!entry.get_app_info().get_nodisplay()) {
|
||||
this._view.addApp(app);
|
||||
appList.push(app);
|
||||
}
|
||||
} else if (nextType == GMenu.TreeItemType.DIRECTORY) {
|
||||
if (!dir.get_is_nodisplay())
|
||||
this._loadCategory(iter.get_directory(), appList);
|
||||
var itemDir = iter.get_directory();
|
||||
if (!itemDir.get_is_nodisplay())
|
||||
this._loadCategory(itemDir, appList);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_addCategory: function(name, index, dir, allApps) {
|
||||
_addCategory: function(name, index, dir) {
|
||||
let button = new St.Button({ label: GLib.markup_escape_text (name, -1),
|
||||
style_class: 'app-filter',
|
||||
x_align: St.Align.START,
|
||||
@ -225,7 +227,6 @@ const ViewByCategories = new Lang.Class({
|
||||
|
||||
var apps;
|
||||
if (dir == null) {
|
||||
apps = allApps;
|
||||
this._allCategoryButton = button;
|
||||
} else {
|
||||
apps = [];
|
||||
@ -239,6 +240,7 @@ const ViewByCategories = new Lang.Class({
|
||||
},
|
||||
|
||||
_removeAll: function() {
|
||||
this._view.removeAll();
|
||||
this._categories = [];
|
||||
this._categoryBox.destroy_all_children();
|
||||
},
|
||||
@ -246,13 +248,8 @@ const ViewByCategories = new Lang.Class({
|
||||
refresh: function() {
|
||||
this._removeAll();
|
||||
|
||||
var allApps = Shell.AppSystem.get_default().get_all();
|
||||
allApps.sort(function(a, b) {
|
||||
return a.compare_by_name(b);
|
||||
});
|
||||
|
||||
/* Translators: Filter to display all applications */
|
||||
this._addCategory(_("All"), -1, null, allApps);
|
||||
this._addCategory(_("All"), -1, null);
|
||||
|
||||
var tree = this._appSystem.get_tree();
|
||||
var root = tree.get_root_directory();
|
||||
@ -270,7 +267,6 @@ const ViewByCategories = new Lang.Class({
|
||||
}
|
||||
}
|
||||
|
||||
this._view.setAppList(allApps);
|
||||
this._selectCategory(-1);
|
||||
|
||||
if (this._focusDummy) {
|
||||
|
@ -123,7 +123,8 @@ const AutomountManager = new Lang.Class({
|
||||
let volumes = this._volumeMonitor.get_volumes();
|
||||
volumes.forEach(Lang.bind(this, function(volume) {
|
||||
this._checkAndMountVolume(volume, { checkSession: false,
|
||||
useMountOp: false });
|
||||
useMountOp: false,
|
||||
allowAutorun: false });
|
||||
}));
|
||||
|
||||
return false;
|
||||
@ -201,7 +202,8 @@ const AutomountManager = new Lang.Class({
|
||||
|
||||
_checkAndMountVolume: function(volume, params) {
|
||||
params = Params.parse(params, { checkSession: true,
|
||||
useMountOp: true });
|
||||
useMountOp: true,
|
||||
allowAutorun: true });
|
||||
|
||||
if (params.checkSession) {
|
||||
// if we're not in the current ConsoleKit session,
|
||||
@ -236,15 +238,20 @@ const AutomountManager = new Lang.Class({
|
||||
|
||||
if (params.useMountOp) {
|
||||
let operation = new ShellMountOperation.ShellMountOperation(volume);
|
||||
this._mountVolume(volume, operation.mountOp);
|
||||
this._mountVolume(volume, operation, params.allowAutorun);
|
||||
} else {
|
||||
this._mountVolume(volume, null);
|
||||
this._mountVolume(volume, null, params.allowAutorun);
|
||||
}
|
||||
},
|
||||
|
||||
_mountVolume: function(volume, operation) {
|
||||
this._allowAutorun(volume);
|
||||
volume.mount(0, operation, null,
|
||||
_mountVolume: function(volume, operation, allowAutorun) {
|
||||
if (allowAutorun)
|
||||
this._allowAutorun(volume);
|
||||
|
||||
let mountOp = operation ? operation.mountOp : null;
|
||||
volume._operation = operation;
|
||||
|
||||
volume.mount(0, mountOp, null,
|
||||
Lang.bind(this, this._onVolumeMounted));
|
||||
},
|
||||
|
||||
@ -253,15 +260,19 @@ const AutomountManager = new Lang.Class({
|
||||
|
||||
try {
|
||||
volume.mount_finish(res);
|
||||
this._closeOperation(volume);
|
||||
} 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)
|
||||
// FIXME: we will always get G_IO_ERROR_FAILED from the gvfs udisks
|
||||
// backend in this case, see
|
||||
// https://bugs.freedesktop.org/show_bug.cgi?id=51271
|
||||
if (e.message.indexOf('No key available with this passphrase') != -1) {
|
||||
this._reaskPassword(volume);
|
||||
else
|
||||
log('Unable to mount volume ' + volume.get_name() + ': ' + string);
|
||||
} else {
|
||||
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.FAILED_HANDLED))
|
||||
log('Unable to mount volume ' + volume.get_name() + ': ' + e.toString());
|
||||
|
||||
this._closeOperation(volume);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -273,8 +284,16 @@ const AutomountManager = new Lang.Class({
|
||||
},
|
||||
|
||||
_reaskPassword: function(volume) {
|
||||
let operation = new ShellMountOperation.ShellMountOperation(volume, { reaskPassword: true });
|
||||
this._mountVolume(volume, operation.mountOp);
|
||||
let existingDialog = volume._operation ? volume._operation.borrowDialog() : null;
|
||||
let operation =
|
||||
new ShellMountOperation.ShellMountOperation(volume,
|
||||
{ existingDialog: existingDialog });
|
||||
this._mountVolume(volume, operation);
|
||||
},
|
||||
|
||||
_closeOperation: function(volume) {
|
||||
if (volume._operation)
|
||||
volume._operation.close();
|
||||
},
|
||||
|
||||
_allowAutorun: function(volume) {
|
||||
|
@ -23,12 +23,14 @@ const AutorunSetting = {
|
||||
};
|
||||
|
||||
// misc utils
|
||||
function ignoreAutorunForMount(mount) {
|
||||
function shouldAutorunMount(mount, forTransient) {
|
||||
let root = mount.get_root();
|
||||
let volume = mount.get_volume();
|
||||
|
||||
if ((root.is_native() && !isMountRootHidden(root)) ||
|
||||
(volume && volume.allowAutorun && volume.should_automount()))
|
||||
if (!volume || (!volume.allowAutorun && forTransient))
|
||||
return false;
|
||||
|
||||
if (!root.is_native() || isMountRootHidden(root))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -224,11 +226,9 @@ const AutorunManager = new Lang.Class({
|
||||
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());
|
||||
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.FAILED_HANDLED))
|
||||
log('Unable to eject the mount ' + mount.get_name()
|
||||
+ ': ' + e.toString());
|
||||
}
|
||||
},
|
||||
|
||||
@ -236,11 +236,9 @@ const AutorunManager = new Lang.Class({
|
||||
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());
|
||||
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.FAILED_HANDLED))
|
||||
log('Unable to eject the drive ' + source.get_name()
|
||||
+ ': ' + e.toString());
|
||||
}
|
||||
},
|
||||
|
||||
@ -248,11 +246,9 @@ const AutorunManager = new Lang.Class({
|
||||
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());
|
||||
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.FAILED_HANDLED))
|
||||
log('Unable to stop the drive ' + drive.get_name()
|
||||
+ ': ' + e.toString());
|
||||
}
|
||||
},
|
||||
});
|
||||
@ -270,7 +266,7 @@ const AutorunResidentSource = new Lang.Class({
|
||||
},
|
||||
|
||||
addMount: function(mount, apps) {
|
||||
if (ignoreAutorunForMount(mount))
|
||||
if (!shouldAutorunMount(mount, false))
|
||||
return;
|
||||
|
||||
let filtered = this._mounts.filter(function (element) {
|
||||
@ -448,7 +444,7 @@ const AutorunTransientDispatcher = new Lang.Class({
|
||||
return;
|
||||
|
||||
// if the mount doesn't want to be autorun, return
|
||||
if (ignoreAutorunForMount(mount))
|
||||
if (!shouldAutorunMount(mount, true))
|
||||
return;
|
||||
|
||||
let setting = this._getAutorunSettingForType(contentTypes[0]);
|
||||
|
@ -448,7 +448,7 @@ const Calendar = new Lang.Class({
|
||||
}
|
||||
|
||||
// All the children after this are days, and get removed when we update the calendar
|
||||
this._firstDayIndex = this.actor.get_children().length;
|
||||
this._firstDayIndex = this.actor.get_n_children();
|
||||
},
|
||||
|
||||
_onStyleChange: function(actor, event) {
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GnomeDesktop = imports.gi.GnomeDesktop;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Cairo = imports.cairo;
|
||||
@ -16,14 +17,6 @@ const Main = imports.ui.main;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const Calendar = imports.ui.calendar;
|
||||
const UPowerGlib = imports.gi.UPowerGlib;
|
||||
|
||||
// in org.gnome.desktop.interface
|
||||
const CLOCK_FORMAT_KEY = 'clock-format';
|
||||
|
||||
// in org.gnome.shell.clock
|
||||
const CLOCK_SHOW_DATE_KEY = 'show-date';
|
||||
const CLOCK_SHOW_SECONDS_KEY = 'show-seconds';
|
||||
|
||||
function _onVertSepRepaint (area)
|
||||
{
|
||||
@ -60,8 +53,8 @@ const DateMenuButton = new Lang.Class({
|
||||
// role ATK_ROLE_MENU like other elements of the panel.
|
||||
this.actor.accessible_role = Atk.Role.LABEL;
|
||||
|
||||
this._clock = new St.Label();
|
||||
this.actor.add_actor(this._clock);
|
||||
this._clockDisplay = new St.Label();
|
||||
this.actor.add_actor(this._clockDisplay);
|
||||
|
||||
hbox = new St.BoxLayout({name: 'calendarArea' });
|
||||
this.menu.addActor(hbox);
|
||||
@ -73,7 +66,7 @@ const DateMenuButton = new Lang.Class({
|
||||
|
||||
// Date
|
||||
this._date = new St.Label();
|
||||
this.actor.label_actor = this._clock;
|
||||
this.actor.label_actor = this._clockDisplay;
|
||||
this._date.style_class = 'datemenu-date-label';
|
||||
vbox.add(this._date);
|
||||
|
||||
@ -155,68 +148,13 @@ const DateMenuButton = new Lang.Class({
|
||||
|
||||
// Done with hbox for calendar and event list
|
||||
|
||||
// Track changes to clock settings
|
||||
this._desktopSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' });
|
||||
this._clockSettings = new Gio.Settings({ schema: 'org.gnome.shell.clock' });
|
||||
this._desktopSettings.connect('changed', Lang.bind(this, this._updateClockAndDate));
|
||||
this._clockSettings.connect('changed', Lang.bind(this, this._updateClockAndDate));
|
||||
|
||||
// https://bugzilla.gnome.org/show_bug.cgi?id=655129
|
||||
this._upClient = new UPowerGlib.Client();
|
||||
this._upClient.connect('notify-resume', Lang.bind(this, this._updateClockAndDate));
|
||||
|
||||
// Start the clock
|
||||
this._clock = new GnomeDesktop.WallClock();
|
||||
this._clock.connect('notify::clock', Lang.bind(this, this._updateClockAndDate));
|
||||
this._updateClockAndDate();
|
||||
},
|
||||
|
||||
_updateClockAndDate: function() {
|
||||
let format = this._desktopSettings.get_string(CLOCK_FORMAT_KEY);
|
||||
let showDate = this._clockSettings.get_boolean(CLOCK_SHOW_DATE_KEY);
|
||||
let showSeconds = this._clockSettings.get_boolean(CLOCK_SHOW_SECONDS_KEY);
|
||||
|
||||
let clockFormat;
|
||||
let dateFormat;
|
||||
|
||||
switch (format) {
|
||||
case '24h':
|
||||
if (showDate)
|
||||
/* Translators: This is the time format with date used
|
||||
in 24-hour mode. */
|
||||
clockFormat = showSeconds ? _("%a %b %e, %R:%S")
|
||||
: _("%a %b %e, %R");
|
||||
else
|
||||
/* Translators: This is the time format without date used
|
||||
in 24-hour mode. */
|
||||
clockFormat = showSeconds ? _("%a %R:%S")
|
||||
: _("%a %R");
|
||||
break;
|
||||
case '12h':
|
||||
default:
|
||||
if (showDate)
|
||||
/* Translators: This is a time format with date used
|
||||
for AM/PM. */
|
||||
clockFormat = showSeconds ? _("%a %b %e, %l:%M:%S %p")
|
||||
: _("%a %b %e, %l:%M %p");
|
||||
else
|
||||
/* Translators: This is a time format without date used
|
||||
for AM/PM. */
|
||||
clockFormat = showSeconds ? _("%a %l:%M:%S %p")
|
||||
: _("%a %l:%M %p");
|
||||
break;
|
||||
}
|
||||
|
||||
let displayDate = new Date();
|
||||
|
||||
this._clock.set_text(displayDate.toLocaleFormat(clockFormat));
|
||||
|
||||
/* Translators: This is the date format to use when the calendar popup is
|
||||
* shown - it is shown just below the time in the shell (e.g. "Tue 9:29 AM").
|
||||
*/
|
||||
dateFormat = _("%A %B %e, %Y");
|
||||
this._date.set_text(displayDate.toLocaleFormat(dateFormat));
|
||||
|
||||
Mainloop.timeout_add_seconds(1, Lang.bind(this, this._updateClockAndDate));
|
||||
return false;
|
||||
this._clockDisplay.set_text(this._clock.clock);
|
||||
},
|
||||
|
||||
_onOpenCalendarActivate: function() {
|
||||
|
@ -31,7 +31,6 @@ const St = imports.gi.St;
|
||||
const Shell = imports.gi.Shell;
|
||||
|
||||
const GnomeSession = imports.misc.gnomeSession;
|
||||
const Lightbox = imports.ui.lightbox;
|
||||
const Main = imports.ui.main;
|
||||
const ModalDialog = imports.ui.modalDialog;
|
||||
const Tweener = imports.ui.tweener;
|
||||
@ -288,13 +287,13 @@ const EndSessionDialog = new Lang.Class({
|
||||
|
||||
this._applicationList.connect('actor-added',
|
||||
Lang.bind(this, function() {
|
||||
if (this._applicationList.get_children().length == 1)
|
||||
if (this._applicationList.get_n_children() == 1)
|
||||
scrollView.show();
|
||||
}));
|
||||
|
||||
this._applicationList.connect('actor-removed',
|
||||
Lang.bind(this, function() {
|
||||
if (this._applicationList.get_children().length == 0)
|
||||
if (this._applicationList.get_n_children() == 0)
|
||||
scrollView.hide();
|
||||
}));
|
||||
|
||||
|
170
js/ui/extensionDownloader.js
Normal file
170
js/ui/extensionDownloader.js
Normal file
@ -0,0 +1,170 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Lang = imports.lang;
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Soup = imports.gi.Soup;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const Config = imports.misc.config;
|
||||
const ExtensionUtils = imports.misc.extensionUtils;
|
||||
const ExtensionSystem = imports.ui.extensionSystem;
|
||||
const FileUtils = imports.misc.fileUtils;
|
||||
const ModalDialog = imports.ui.modalDialog;
|
||||
|
||||
const _signals = ExtensionSystem._signals;
|
||||
|
||||
const REPOSITORY_URL_BASE = 'https://extensions.gnome.org';
|
||||
const REPOSITORY_URL_DOWNLOAD = REPOSITORY_URL_BASE + '/download-extension/%s.shell-extension.zip';
|
||||
const REPOSITORY_URL_INFO = REPOSITORY_URL_BASE + '/extension-info/';
|
||||
|
||||
let _httpSession;
|
||||
|
||||
function installExtensionFromUUID(uuid) {
|
||||
let params = { uuid: uuid,
|
||||
shell_version: Config.PACKAGE_VERSION };
|
||||
|
||||
let message = Soup.form_request_new_from_hash('GET', REPOSITORY_URL_INFO, params);
|
||||
|
||||
_httpSession.queue_message(message,
|
||||
function(session, message) {
|
||||
let info = JSON.parse(message.response_body.data);
|
||||
let dialog = new InstallExtensionDialog(uuid, info);
|
||||
dialog.open(global.get_current_time());
|
||||
});
|
||||
}
|
||||
|
||||
function uninstallExtensionFromUUID(uuid) {
|
||||
let extension = ExtensionUtils.extensions[uuid];
|
||||
if (!extension)
|
||||
return false;
|
||||
|
||||
// Don't try to uninstall system extensions
|
||||
if (extension.type != ExtensionUtils.ExtensionType.PER_USER)
|
||||
return false;
|
||||
|
||||
if (!ExtensionSystem.unloadExtension(uuid))
|
||||
return false;
|
||||
|
||||
FileUtils.recursivelyDeleteDir(extension.dir);
|
||||
return true;
|
||||
}
|
||||
|
||||
function gotExtensionZipFile(session, message, uuid) {
|
||||
if (message.status_code != Soup.KnownStatusCode.OK) {
|
||||
logExtensionError(uuid, 'downloading extension: ' + message.status_code);
|
||||
return;
|
||||
}
|
||||
|
||||
let dir = Gio.File.new_for_path(GLib.build_filenamev([global.userdatadir, 'extensions', uuid]));
|
||||
try {
|
||||
if (!dir.query_exists(null))
|
||||
dir.make_directory_with_parents(null);
|
||||
} catch (e) {
|
||||
logExtensionError('Could not create extension directory');
|
||||
}
|
||||
|
||||
let [file, stream] = Gio.File.new_tmp('XXXXXX.shell-extension.zip');
|
||||
let contents = message.response_body.flatten().as_bytes();
|
||||
stream.output_stream.write_bytes(contents, null);
|
||||
stream.close(null);
|
||||
let [success, pid] = GLib.spawn_async(null,
|
||||
['unzip', '-uod', dir.get_path(), '--', file.get_path()],
|
||||
null,
|
||||
GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD,
|
||||
null);
|
||||
|
||||
if (!success) {
|
||||
logExtensionError(uuid, 'extract: could not extract');
|
||||
return;
|
||||
}
|
||||
|
||||
GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, function(pid, status) {
|
||||
GLib.spawn_close_pid(pid);
|
||||
|
||||
// Add extension to 'enabled-extensions' for the user, always...
|
||||
let enabledExtensions = global.settings.get_strv(ExtensionSystem.ENABLED_EXTENSIONS_KEY);
|
||||
if (enabledExtensions.indexOf(uuid) == -1) {
|
||||
enabledExtensions.push(uuid);
|
||||
global.settings.set_strv(ExtensionSystem.ENABLED_EXTENSIONS_KEY, enabledExtensions);
|
||||
}
|
||||
|
||||
ExtensionSystem.loadExtension(dir, ExtensionUtils.ExtensionType.PER_USER, true);
|
||||
});
|
||||
}
|
||||
|
||||
const InstallExtensionDialog = new Lang.Class({
|
||||
Name: 'InstallExtensionDialog',
|
||||
Extends: ModalDialog.ModalDialog,
|
||||
|
||||
_init: function(uuid, info) {
|
||||
this.parent({ styleClass: 'extension-dialog' });
|
||||
|
||||
this._uuid = uuid;
|
||||
this._info = info;
|
||||
|
||||
this.setButtons([{ label: _("Cancel"),
|
||||
action: Lang.bind(this, this._onCancelButtonPressed),
|
||||
key: Clutter.Escape
|
||||
},
|
||||
{ label: _("Install"),
|
||||
action: Lang.bind(this, this._onInstallButtonPressed)
|
||||
}]);
|
||||
|
||||
let message = _("Download and install '%s' from extensions.gnome.org?").format(info.name);
|
||||
|
||||
let box = new St.BoxLayout();
|
||||
this.contentLayout.add(box);
|
||||
|
||||
let gicon = new Gio.FileIcon({ file: Gio.File.new_for_uri(REPOSITORY_URL_BASE + info.icon) })
|
||||
let icon = new St.Icon({ gicon: gicon });
|
||||
box.add(icon);
|
||||
|
||||
let label = new St.Label({ text: message });
|
||||
box.add(label);
|
||||
},
|
||||
|
||||
_onCancelButtonPressed: function(button, event) {
|
||||
this.close(global.get_current_time());
|
||||
|
||||
// Even though the extension is already "uninstalled", send through
|
||||
// a state-changed signal for any users who want to know if the install
|
||||
// went through correctly -- using proper async DBus would block more
|
||||
// traditional clients like the plugin
|
||||
let meta = { uuid: this._uuid,
|
||||
state: ExtensionSystem.ExtensionState.UNINSTALLED,
|
||||
error: '' };
|
||||
|
||||
_signals.emit('extension-state-changed', meta);
|
||||
},
|
||||
|
||||
_onInstallButtonPressed: function(button, event) {
|
||||
let state = { uuid: this._uuid,
|
||||
state: ExtensionSystem.ExtensionState.DOWNLOADING,
|
||||
error: '' };
|
||||
|
||||
_signals.emit('extension-state-changed', state);
|
||||
|
||||
let params = { shell_version: Config.PACKAGE_VERSION };
|
||||
|
||||
let url = REPOSITORY_URL_DOWNLOAD.format(this._uuid);
|
||||
let message = Soup.form_request_new_from_hash('GET', url, params);
|
||||
|
||||
_httpSession.queue_message(message,
|
||||
Lang.bind(this, function(session, message) {
|
||||
gotExtensionZipFile(session, message, this._uuid);
|
||||
}));
|
||||
|
||||
this.close(global.get_current_time());
|
||||
}
|
||||
});
|
||||
|
||||
function init() {
|
||||
_httpSession = new Soup.SessionAsync({ ssl_use_system_ca_file: true });
|
||||
|
||||
// See: https://bugzilla.gnome.org/show_bug.cgi?id=655189 for context.
|
||||
// _httpSession.add_feature(new Soup.ProxyResolverDefault());
|
||||
Soup.Session.prototype.add_feature.call(_httpSession, new Soup.ProxyResolverDefault());
|
||||
}
|
@ -3,19 +3,11 @@
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gio = imports.gi.Gio;
|
||||
const St = imports.gi.St;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Soup = imports.gi.Soup;
|
||||
|
||||
const Config = imports.misc.config;
|
||||
const ExtensionUtils = imports.misc.extensionUtils;
|
||||
const FileUtils = imports.misc.fileUtils;
|
||||
const ModalDialog = imports.ui.modalDialog;
|
||||
|
||||
const API_VERSION = 1;
|
||||
|
||||
const ExtensionState = {
|
||||
ENABLED: 1,
|
||||
@ -30,16 +22,6 @@ const ExtensionState = {
|
||||
UNINSTALLED: 99
|
||||
};
|
||||
|
||||
const REPOSITORY_URL_BASE = 'https://extensions.gnome.org';
|
||||
const REPOSITORY_URL_DOWNLOAD = REPOSITORY_URL_BASE + '/download-extension/%s.shell-extension.zip';
|
||||
const REPOSITORY_URL_INFO = REPOSITORY_URL_BASE + '/extension-info/';
|
||||
|
||||
const _httpSession = new Soup.SessionAsync({ ssl_use_system_ca_file: true });
|
||||
|
||||
// See: https://bugzilla.gnome.org/show_bug.cgi?id=655189 for context.
|
||||
// _httpSession.add_feature(new Soup.ProxyResolverDefault());
|
||||
Soup.Session.prototype.add_feature.call(_httpSession, new Soup.ProxyResolverDefault());
|
||||
|
||||
// Arrays of uuids
|
||||
var enabledExtensions;
|
||||
// Contains the order that extensions were enabled in.
|
||||
@ -56,80 +38,6 @@ const disconnect = Lang.bind(_signals, _signals.disconnect);
|
||||
|
||||
const ENABLED_EXTENSIONS_KEY = 'enabled-extensions';
|
||||
|
||||
function installExtensionFromUUID(uuid) {
|
||||
let params = { uuid: uuid,
|
||||
shell_version: Config.PACKAGE_VERSION };
|
||||
|
||||
let message = Soup.form_request_new_from_hash('GET', REPOSITORY_URL_INFO, params);
|
||||
|
||||
_httpSession.queue_message(message,
|
||||
function(session, message) {
|
||||
let info = JSON.parse(message.response_body.data);
|
||||
let dialog = new InstallExtensionDialog(uuid, info);
|
||||
dialog.open(global.get_current_time());
|
||||
});
|
||||
}
|
||||
|
||||
function uninstallExtensionFromUUID(uuid) {
|
||||
let extension = ExtensionUtils.extensions[uuid];
|
||||
if (!extension)
|
||||
return false;
|
||||
|
||||
// Try to disable it -- if it's ERROR'd, we can't guarantee that,
|
||||
// but it will be removed on next reboot, and hopefully nothing
|
||||
// broke too much.
|
||||
disableExtension(uuid);
|
||||
|
||||
// Don't try to uninstall system extensions
|
||||
if (extension.type != ExtensionUtils.ExtensionType.PER_USER)
|
||||
return false;
|
||||
|
||||
extension.state = ExtensionState.UNINSTALLED;
|
||||
_signals.emit('extension-state-changed', extension);
|
||||
|
||||
delete ExtensionUtils.extensions[uuid];
|
||||
|
||||
FileUtils.recursivelyDeleteDir(Gio.file_new_for_path(extension.path));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function gotExtensionZipFile(session, message, uuid) {
|
||||
if (message.status_code != Soup.KnownStatusCode.OK) {
|
||||
logExtensionError(uuid, 'downloading extension: ' + message.status_code);
|
||||
return;
|
||||
}
|
||||
|
||||
let [file, stream] = Gio.File.new_tmp('XXXXXX.shell-extension.zip');
|
||||
let dir = ExtensionUtils.userExtensionsDir.get_child(uuid);
|
||||
let contents = message.response_body.flatten().as_bytes();
|
||||
stream.output_stream.write_bytes(contents, null);
|
||||
stream.close(null);
|
||||
let [success, pid] = GLib.spawn_async(null,
|
||||
['unzip', '-uod', dir.get_path(), '--', file.get_path()],
|
||||
null,
|
||||
GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD,
|
||||
null);
|
||||
|
||||
if (!success) {
|
||||
logExtensionError(uuid, 'extract: could not extract');
|
||||
return;
|
||||
}
|
||||
|
||||
GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, function(pid, status) {
|
||||
GLib.spawn_close_pid(pid);
|
||||
|
||||
// Add extension to 'enabled-extensions' for the user, always...
|
||||
let enabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
|
||||
if (enabledExtensions.indexOf(uuid) == -1) {
|
||||
enabledExtensions.push(uuid);
|
||||
global.settings.set_strv(ENABLED_EXTENSIONS_KEY, enabledExtensions);
|
||||
}
|
||||
|
||||
loadExtension(dir, ExtensionUtils.ExtensionType.PER_USER, true);
|
||||
});
|
||||
}
|
||||
|
||||
function disableExtension(uuid) {
|
||||
let extension = ExtensionUtils.extensions[uuid];
|
||||
if (!extension)
|
||||
@ -159,6 +67,11 @@ function disableExtension(uuid) {
|
||||
}
|
||||
}
|
||||
|
||||
if (extension.stylesheet) {
|
||||
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
|
||||
theme.unload_stylesheet(extension.stylesheet.get_path());
|
||||
}
|
||||
|
||||
try {
|
||||
extension.stateObj.disable();
|
||||
} catch(e) {
|
||||
@ -201,6 +114,17 @@ function enableExtension(uuid) {
|
||||
return;
|
||||
}
|
||||
|
||||
let stylesheetFile = extension.dir.get_child('stylesheet.css');
|
||||
if (stylesheetFile.query_exists(null)) {
|
||||
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
|
||||
try {
|
||||
theme.load_stylesheet(stylesheetFile.get_path());
|
||||
extension.stylesheet = stylesheetFile;
|
||||
} catch (e) {
|
||||
logExtensionError(uuid, 'Stylesheet parse error: ' + e);
|
||||
}
|
||||
}
|
||||
|
||||
extension.state = ExtensionState.ENABLED;
|
||||
_signals.emit('extension-state-changed', extension);
|
||||
}
|
||||
@ -221,35 +145,21 @@ function logExtensionError(uuid, message, state) {
|
||||
state: state });
|
||||
}
|
||||
|
||||
function loadExtension(dir, type, enabled) {
|
||||
let uuid = dir.get_basename();
|
||||
let extension;
|
||||
|
||||
if (ExtensionUtils.extensions[uuid] != undefined) {
|
||||
log('Extension "%s" is already loaded'.format(uuid));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
extension = ExtensionUtils.createExtensionObject(uuid, dir, type);
|
||||
} catch(e) {
|
||||
logExtensionError(uuid, e.message);
|
||||
return;
|
||||
}
|
||||
|
||||
function loadExtension(extension) {
|
||||
// Default to error, we set success as the last step
|
||||
extension.state = ExtensionState.ERROR;
|
||||
|
||||
if (ExtensionUtils.isOutOfDate(extension)) {
|
||||
logExtensionError(uuid, 'extension is not compatible with current GNOME Shell and/or GJS version', ExtensionState.OUT_OF_DATE);
|
||||
logExtensionError(extension.uuid, 'extension is not compatible with current GNOME Shell and/or GJS version', ExtensionState.OUT_OF_DATE);
|
||||
extension.state = ExtensionState.OUT_OF_DATE;
|
||||
return;
|
||||
}
|
||||
|
||||
let enabled = enabledExtensions.indexOf(extension.uuid) != -1;
|
||||
if (enabled) {
|
||||
initExtension(uuid);
|
||||
initExtension(extension.uuid);
|
||||
if (extension.state == ExtensionState.DISABLED)
|
||||
enableExtension(uuid);
|
||||
enableExtension(extension.uuid);
|
||||
} else {
|
||||
extension.state = ExtensionState.INITIALIZED;
|
||||
}
|
||||
@ -257,6 +167,23 @@ function loadExtension(dir, type, enabled) {
|
||||
_signals.emit('extension-state-changed', extension);
|
||||
}
|
||||
|
||||
function unloadExtension(uuid) {
|
||||
let extension = ExtensionUtils.extensions[uuid];
|
||||
if (!extension)
|
||||
return false;
|
||||
|
||||
// Try to disable it -- if it's ERROR'd, we can't guarantee that,
|
||||
// but it will be removed on next reboot, and hopefully nothing
|
||||
// broke too much.
|
||||
disableExtension(uuid);
|
||||
|
||||
extension.state = ExtensionState.UNINSTALLED;
|
||||
_signals.emit('extension-state-changed', extension);
|
||||
|
||||
delete ExtensionUtils.extensions[uuid];
|
||||
return true;
|
||||
}
|
||||
|
||||
function initExtension(uuid) {
|
||||
let extension = ExtensionUtils.extensions[uuid];
|
||||
let dir = extension.dir;
|
||||
@ -269,18 +196,6 @@ function initExtension(uuid) {
|
||||
logExtensionError(uuid, 'Missing extension.js');
|
||||
return;
|
||||
}
|
||||
let stylesheetPath = null;
|
||||
let themeContext = St.ThemeContext.get_for_stage(global.stage);
|
||||
let theme = themeContext.get_theme();
|
||||
let stylesheetFile = dir.get_child('stylesheet.css');
|
||||
if (stylesheetFile.query_exists(null)) {
|
||||
try {
|
||||
theme.load_stylesheet(stylesheetFile.get_path());
|
||||
} catch (e) {
|
||||
logExtensionError(uuid, 'Stylesheet parse error: ' + e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let extensionModule;
|
||||
let extensionState = null;
|
||||
@ -288,24 +203,17 @@ function initExtension(uuid) {
|
||||
ExtensionUtils.installImporter(extension);
|
||||
extensionModule = extension.imports.extension;
|
||||
} catch (e) {
|
||||
if (stylesheetPath != null)
|
||||
theme.unload_stylesheet(stylesheetPath);
|
||||
logExtensionError(uuid, '' + e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!extensionModule.init) {
|
||||
logExtensionError(uuid, 'missing \'init\' function');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
extensionState = extensionModule.init(extension);
|
||||
} catch (e) {
|
||||
if (stylesheetPath != null)
|
||||
theme.unload_stylesheet(stylesheetPath);
|
||||
logExtensionError(uuid, 'Failed to evaluate init function:' + e);
|
||||
return;
|
||||
if (extensionModule.init) {
|
||||
try {
|
||||
extensionState = extensionModule.init(extension);
|
||||
} catch (e) {
|
||||
logExtensionError(uuid, 'Failed to evaluate init function:' + e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!extensionState)
|
||||
@ -348,82 +256,13 @@ function onEnabledExtensionsChanged() {
|
||||
enabledExtensions = newEnabledExtensions;
|
||||
}
|
||||
|
||||
function init() {
|
||||
ExtensionUtils.init();
|
||||
|
||||
function loadExtensions() {
|
||||
global.settings.connect('changed::' + ENABLED_EXTENSIONS_KEY, onEnabledExtensionsChanged);
|
||||
enabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
|
||||
}
|
||||
|
||||
function loadExtensions() {
|
||||
ExtensionUtils.scanExtensions(function(uuid, dir, type) {
|
||||
let enabled = enabledExtensions.indexOf(uuid) != -1;
|
||||
loadExtension(dir, type, enabled);
|
||||
let finder = new ExtensionUtils.ExtensionFinder();
|
||||
finder.connect('extension-found', function(signals, extension) {
|
||||
loadExtension(extension);
|
||||
});
|
||||
finder.scanExtensions();
|
||||
}
|
||||
|
||||
const InstallExtensionDialog = new Lang.Class({
|
||||
Name: 'InstallExtensionDialog',
|
||||
Extends: ModalDialog.ModalDialog,
|
||||
|
||||
_init: function(uuid, info) {
|
||||
this.parent({ styleClass: 'extension-dialog' });
|
||||
|
||||
this._uuid = uuid;
|
||||
this._info = info;
|
||||
|
||||
this.setButtons([{ label: _("Cancel"),
|
||||
action: Lang.bind(this, this._onCancelButtonPressed),
|
||||
key: Clutter.Escape
|
||||
},
|
||||
{ label: _("Install"),
|
||||
action: Lang.bind(this, this._onInstallButtonPressed)
|
||||
}]);
|
||||
|
||||
let message = _("Download and install '%s' from extensions.gnome.org?").format(info.name);
|
||||
|
||||
let box = new St.BoxLayout();
|
||||
this.contentLayout.add(box);
|
||||
|
||||
let gicon = new Gio.FileIcon({ file: Gio.File.new_for_uri(REPOSITORY_URL_BASE + info.icon) })
|
||||
let icon = new St.Icon({ gicon: gicon });
|
||||
box.add(icon);
|
||||
|
||||
let label = new St.Label({ text: message });
|
||||
box.add(label);
|
||||
},
|
||||
|
||||
_onCancelButtonPressed: function(button, event) {
|
||||
this.close(global.get_current_time());
|
||||
|
||||
// Even though the extension is already "uninstalled", send through
|
||||
// a state-changed signal for any users who want to know if the install
|
||||
// went through correctly -- using proper async DBus would block more
|
||||
// traditional clients like the plugin
|
||||
let meta = { uuid: this._uuid,
|
||||
state: ExtensionState.UNINSTALLED,
|
||||
error: '' };
|
||||
|
||||
_signals.emit('extension-state-changed', meta);
|
||||
},
|
||||
|
||||
_onInstallButtonPressed: function(button, event) {
|
||||
let state = { uuid: this._uuid,
|
||||
state: ExtensionState.DOWNLOADING,
|
||||
error: '' };
|
||||
|
||||
_signals.emit('extension-state-changed', state);
|
||||
|
||||
let params = { shell_version: Config.PACKAGE_VERSION };
|
||||
|
||||
let url = REPOSITORY_URL_DOWNLOAD.format(this._uuid);
|
||||
let message = Soup.form_request_new_from_hash('GET', url, params);
|
||||
|
||||
_httpSession.queue_message(message,
|
||||
Lang.bind(this, function(session, message) {
|
||||
gotExtensionZipFile(session, message, this._uuid);
|
||||
}));
|
||||
|
||||
this.close(global.get_current_time());
|
||||
}
|
||||
});
|
||||
|
@ -309,21 +309,22 @@ const IconGrid = new Lang.Class({
|
||||
this._grid.queue_relayout();
|
||||
},
|
||||
|
||||
removeAll: function () {
|
||||
this._grid.get_children().forEach(Lang.bind(this, function (child) {
|
||||
child.destroy();
|
||||
}));
|
||||
removeAll: function() {
|
||||
this._grid.destroy_all_children();
|
||||
},
|
||||
|
||||
addItem: function(actor) {
|
||||
this._grid.add_actor(actor);
|
||||
addItem: function(actor, index) {
|
||||
if (index !== undefined)
|
||||
this._grid.insert_child_at_index(actor, index);
|
||||
else
|
||||
this._grid.add_actor(actor);
|
||||
},
|
||||
|
||||
getItemAtIndex: function(index) {
|
||||
return this._grid.get_children()[index];
|
||||
return this._grid.get_child_at_index(index);
|
||||
},
|
||||
|
||||
visibleItemsCount: function() {
|
||||
return this._grid.get_children().length - this._grid.get_n_skip_paint();
|
||||
return this._grid.get_n_children() - this._grid.get_n_skip_paint();
|
||||
}
|
||||
});
|
||||
|
@ -53,6 +53,10 @@ const LayoutManager = new Lang.Class({
|
||||
global.screen.connect('monitors-changed',
|
||||
Lang.bind(this, this._monitorsChanged));
|
||||
this._monitorsChanged();
|
||||
|
||||
this._chrome.connect('primary-fullscreen-changed', Lang.bind(this, function(chrome, state) {
|
||||
this.emit('primary-fullscreen-changed', state);
|
||||
}));
|
||||
},
|
||||
|
||||
// This is called by Main after everything else is constructed;
|
||||
@ -224,26 +228,9 @@ const LayoutManager = new Lang.Class({
|
||||
return false;
|
||||
},
|
||||
|
||||
get focusIndex() {
|
||||
let focusWindow = global.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];
|
||||
get currentMonitor() {
|
||||
let index = global.screen.get_current_monitor();
|
||||
return Main.layoutManager.monitors[index];
|
||||
},
|
||||
|
||||
_startupAnimation: function() {
|
||||
@ -852,6 +839,8 @@ const Chrome = new Lang.Class({
|
||||
for (let i = 0; i < this._monitors.length; i++)
|
||||
wasInFullscreen[i] = this._monitors[i].inFullscreen;
|
||||
|
||||
let primaryWasInFullscreen = this._primaryMonitor.inFullscreen;
|
||||
|
||||
this._updateFullscreen();
|
||||
|
||||
let changed = false;
|
||||
@ -861,10 +850,15 @@ const Chrome = new Lang.Class({
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
this._updateVisibility();
|
||||
this._queueUpdateRegions();
|
||||
}
|
||||
|
||||
if (primaryWasInFullscreen != this._primaryMonitor.inFullscreen) {
|
||||
this.emit('primary-fullscreen-changed', this._primaryMonitor.inFullscreen);
|
||||
}
|
||||
},
|
||||
|
||||
updateRegions: function() {
|
||||
@ -979,3 +973,5 @@ const Chrome = new Lang.Class({
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
Signals.addSignalMethods(Chrome.prototype);
|
||||
|
@ -38,7 +38,7 @@ var commandHeader = 'const Clutter = imports.gi.Clutter; ' +
|
||||
'const stage = global.stage; ' +
|
||||
'const color = function(pixel) { let c= new Clutter.Color(); c.from_pixel(pixel); return c; }; ' +
|
||||
/* Special lookingGlass functions */
|
||||
'const it = Main.lookingGlass.getIt(); ' +
|
||||
'const it = Main.lookingGlass.getIt(); ' +
|
||||
'const r = Lang.bind(Main.lookingGlass, Main.lookingGlass.getResult); ';
|
||||
|
||||
const HISTORY_KEY = 'looking-glass-history';
|
||||
@ -320,7 +320,7 @@ const WindowList = new Lang.Class({
|
||||
},
|
||||
|
||||
_updateWindowList: function() {
|
||||
this.actor.get_children().forEach(function (actor) { actor.destroy(); });
|
||||
this.actor.destroy_all_children();
|
||||
let windows = global.get_window_actors();
|
||||
let tracker = Shell.WindowTracker.get_default();
|
||||
for (let i = 0; i < windows.length; i++) {
|
||||
@ -378,7 +378,7 @@ const ObjInspector = new Lang.Class({
|
||||
this._previousObj = null;
|
||||
this._obj = obj;
|
||||
|
||||
this._container.get_children().forEach(function (child) { child.destroy(); });
|
||||
this._container.destroy_all_children();
|
||||
|
||||
let hbox = new St.BoxLayout({ style_class: 'lg-obj-inspector-title' });
|
||||
this._container.add_actor(hbox);
|
||||
|
@ -18,6 +18,7 @@ const PolkitAuthenticationAgent = imports.ui.polkitAuthenticationAgent;
|
||||
const KeyringPrompt = imports.ui.keyringPrompt;
|
||||
const Environment = imports.ui.environment;
|
||||
const ExtensionSystem = imports.ui.extensionSystem;
|
||||
const ExtensionDownloader = imports.ui.extensionDownloader;
|
||||
const Keyboard = imports.ui.keyboard;
|
||||
const MessageTray = imports.ui.messageTray;
|
||||
const Overview = imports.ui.overview;
|
||||
@ -32,6 +33,7 @@ const WindowAttentionHandler = imports.ui.windowAttentionHandler;
|
||||
const Scripting = imports.ui.scripting;
|
||||
const SessionMode = imports.ui.sessionMode;
|
||||
const ShellDBus = imports.ui.shellDBus;
|
||||
const ShellMountOperation = imports.ui.shellMountOperation;
|
||||
const TelepathyClient = imports.ui.telepathyClient;
|
||||
const WindowManager = imports.ui.windowManager;
|
||||
const Magnifier = imports.ui.magnifier;
|
||||
@ -59,6 +61,7 @@ let ctrlAltTabManager = null;
|
||||
let recorder = null;
|
||||
let sessionMode = null;
|
||||
let shellDBusService = null;
|
||||
let shellMountOpDBusService = null;
|
||||
let modalCount = 0;
|
||||
let modalActorFocusStack = [];
|
||||
let uiGroup = null;
|
||||
@ -149,6 +152,7 @@ function start() {
|
||||
|
||||
sessionMode = new SessionMode.SessionMode();
|
||||
shellDBusService = new ShellDBus.GnomeShell();
|
||||
shellMountOpDBusService = new ShellMountOperation.GnomeShellMountOpHandler();
|
||||
|
||||
// Ensure ShellWindowTracker and ShellAppUsage are initialized; this will
|
||||
// also initialize ShellAppSystem first. ShellAppSystem
|
||||
@ -220,7 +224,7 @@ function start() {
|
||||
false, -1, 1);
|
||||
|
||||
if (sessionMode.allowExtensions) {
|
||||
ExtensionSystem.init();
|
||||
ExtensionDownloader.init();
|
||||
ExtensionSystem.loadExtensions();
|
||||
}
|
||||
|
||||
@ -670,6 +674,7 @@ function pushModal(actor, timestamp, options) {
|
||||
log('pushModal: invocation of begin_modal failed');
|
||||
return false;
|
||||
}
|
||||
Meta.disable_unredirect_for_screen(global.screen);
|
||||
}
|
||||
|
||||
global.set_stage_input_mode(Shell.StageInputMode.FULLSCREEN);
|
||||
@ -750,6 +755,7 @@ function popModal(actor, timestamp) {
|
||||
|
||||
global.end_modal(timestamp);
|
||||
global.set_stage_input_mode(Shell.StageInputMode.NORMAL);
|
||||
Meta.enable_unredirect_for_screen(global.screen);
|
||||
}
|
||||
|
||||
function createLookingGlass() {
|
||||
|
@ -756,7 +756,7 @@ const Notification = new Lang.Class({
|
||||
button.label = label;
|
||||
}
|
||||
|
||||
if (this._buttonBox.get_children().length > 0)
|
||||
if (this._buttonBox.get_n_children() > 0)
|
||||
this._buttonFocusManager.remove_group(this._buttonBox);
|
||||
|
||||
this._buttonBox.add(button);
|
||||
@ -1284,7 +1284,7 @@ const SummaryItem = new Lang.Class({
|
||||
},
|
||||
|
||||
prepareNotificationStackForShowing: function() {
|
||||
if (this.notificationStack.get_children().length > 0)
|
||||
if (this.notificationStack.get_n_children() > 0)
|
||||
return;
|
||||
|
||||
for (let i = 0; i < this.source.notifications.length; i++) {
|
||||
@ -1293,7 +1293,6 @@ const SummaryItem = new Lang.Class({
|
||||
},
|
||||
|
||||
doneShowingNotificationStack: function() {
|
||||
let notificationActors = this.notificationStack.get_children();
|
||||
for (let i = 0; i < this._stackedNotifications.length; i++) {
|
||||
let stackedNotification = this._stackedNotifications[i];
|
||||
let notification = stackedNotification.notification;
|
||||
@ -1323,7 +1322,7 @@ const SummaryItem = new Lang.Class({
|
||||
this._stackedNotifications.push(stackedNotification);
|
||||
if (!this.source.isChat)
|
||||
notification.enableScrolling(false);
|
||||
if (this.notificationStack.get_children().length > 0)
|
||||
if (this.notificationStack.get_n_children() > 0)
|
||||
notification.setIconVisible(false);
|
||||
this.notificationStack.add(notification.actor);
|
||||
notification.expand(false);
|
||||
@ -1469,6 +1468,7 @@ const MessageTray = new Lang.Class({
|
||||
this._overviewVisible = Main.overview.visible;
|
||||
this._notificationRemoved = false;
|
||||
this._reNotifyAfterHideNotification = null;
|
||||
this._inFullscreen = false;
|
||||
|
||||
this._corner = new Clutter.Rectangle({ width: 1,
|
||||
height: 1,
|
||||
@ -1484,6 +1484,7 @@ const MessageTray = new Lang.Class({
|
||||
Main.layoutManager.trackChrome(this._notificationBin);
|
||||
|
||||
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._setSizePosition));
|
||||
Main.layoutManager.connect('primary-fullscreen-changed', Lang.bind(this, this._onFullscreenChanged));
|
||||
|
||||
this._setSizePosition();
|
||||
|
||||
@ -1957,6 +1958,11 @@ const MessageTray = new Lang.Class({
|
||||
this._updateState();
|
||||
},
|
||||
|
||||
_onFullscreenChanged: function(obj, state) {
|
||||
this._inFullscreen = state;
|
||||
this._updateState();
|
||||
},
|
||||
|
||||
_onStatusChanged: function(status) {
|
||||
if (status == GnomeSession.PresenceStatus.BUSY) {
|
||||
// remove notification and allow the summary to be closed now
|
||||
@ -2014,7 +2020,7 @@ const MessageTray = new Lang.Class({
|
||||
_updateState: function() {
|
||||
// Notifications
|
||||
let notificationUrgent = this._notificationQueue.length > 0 && this._notificationQueue[0].urgency == Urgency.CRITICAL;
|
||||
let notificationsPending = this._notificationQueue.length > 0 && (!this._busy || notificationUrgent);
|
||||
let notificationsPending = this._notificationQueue.length > 0 && ((!this._busy && !this._inFullscreen) || notificationUrgent);
|
||||
let notificationPinned = this._pointerInTray && !this._pointerInSummary && !this._notificationRemoved;
|
||||
let notificationExpanded = this._notificationBin.y < 0;
|
||||
let notificationExpired = (this._notificationTimeoutId == 0 && !(this._notification && this._notification.urgency == Urgency.CRITICAL) && !this._pointerInTray && !this._locked && !(this._pointerInKeyboard && notificationExpanded)) || this._notificationRemoved;
|
||||
@ -2050,7 +2056,7 @@ const MessageTray = new Lang.Class({
|
||||
if (this._summaryState == State.HIDDEN && !mustHideSummary) {
|
||||
if (summarySummoned) {
|
||||
this._showSummary(0);
|
||||
} else if (notificationsDone && !this._busy) {
|
||||
} else if (notificationsDone && !this._busy && !this._inFullscreen) {
|
||||
if (this._backFromAway && this._unseenNotifications.length > 0)
|
||||
this._showSummary(LONGER_SUMMARY_TIMEOUT);
|
||||
else if (this._newSummaryItems.length > 0)
|
||||
@ -2429,7 +2435,7 @@ const MessageTray = new Lang.Class({
|
||||
},
|
||||
|
||||
_onSummaryBoxPointerContentUpdated: function() {
|
||||
if (this._summaryBoxPointerItem.notificationStack.get_children().length == 0)
|
||||
if (this._summaryBoxPointerItem.notificationStack.get_n_children() == 0)
|
||||
this._hideSummaryBoxPointer();
|
||||
this._adjustSummaryBoxPointerPosition();
|
||||
|
||||
@ -2463,7 +2469,7 @@ const MessageTray = new Lang.Class({
|
||||
// We should be sure to hide the box pointer if all notifications in it are destroyed while
|
||||
// it is hiding, so that we don't show an an animation of an empty blob being hidden.
|
||||
if (this._summaryBoxPointerState == State.HIDING &&
|
||||
this._summaryBoxPointerItem.notificationStack.get_children().length == 0) {
|
||||
this._summaryBoxPointerItem.notificationStack.get_n_children() == 0) {
|
||||
this._summaryBoxPointer.actor.hide();
|
||||
return;
|
||||
}
|
||||
|
@ -180,7 +180,7 @@ const ModalDialog = new Lang.Class({
|
||||
},
|
||||
|
||||
_fadeOpen: function() {
|
||||
let monitor = Main.layoutManager.focusMonitor;
|
||||
let monitor = Main.layoutManager.currentMonitor;
|
||||
|
||||
this._backgroundBin.set_position(monitor.x, monitor.y);
|
||||
this._backgroundBin.set_size(monitor.width, monitor.height);
|
||||
|
@ -1,6 +1,7 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Config = imports.misc.config;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Mainloop = imports.mainloop;
|
||||
@ -11,10 +12,9 @@ const Shell = imports.gi.Shell;
|
||||
const Gdk = imports.gi.Gdk;
|
||||
|
||||
const AppDisplay = imports.ui.appDisplay;
|
||||
const ContactDisplay = imports.ui.contactDisplay;
|
||||
const ContactDisplay = Config.HAVE_FOLKS ? imports.ui.contactDisplay : null;
|
||||
const Dash = imports.ui.dash;
|
||||
const DND = imports.ui.dnd;
|
||||
const Lightbox = imports.ui.lightbox;
|
||||
const Main = imports.ui.main;
|
||||
const MessageTray = imports.ui.messageTray;
|
||||
const Panel = imports.ui.panel;
|
||||
@ -208,7 +208,8 @@ const Overview = new Lang.Class({
|
||||
this.addSearchProvider(new AppDisplay.AppSearchProvider());
|
||||
this.addSearchProvider(new AppDisplay.SettingsSearchProvider());
|
||||
this.addSearchProvider(new PlaceDisplay.PlaceSearchProvider());
|
||||
this.addSearchProvider(new ContactDisplay.ContactSearchProvider());
|
||||
if (ContactDisplay != null)
|
||||
this.addSearchProvider(new ContactDisplay.ContactSearchProvider());
|
||||
|
||||
// Load remote search providers provided by applications
|
||||
RemoteSearch.loadRemoteSearchProviders(Lang.bind(this, this.addSearchProvider));
|
||||
|
@ -906,7 +906,7 @@ const PopupMenuBase = new Lang.Class({
|
||||
},
|
||||
|
||||
isEmpty: function() {
|
||||
return this.box.get_children().length == 0;
|
||||
return this.box.get_n_children() == 0;
|
||||
},
|
||||
|
||||
isChildMenu: function(menu) {
|
||||
|
@ -62,10 +62,25 @@ function loadRemoteSearchProvidersFromDir(dir, addProviderCallback) {
|
||||
let remoteProvider, title;
|
||||
try {
|
||||
let group = KEY_FILE_GROUP;
|
||||
let icon = keyfile.get_string(group, 'Icon');
|
||||
let busName = keyfile.get_string(group, 'BusName');
|
||||
let objectPath = keyfile.get_string(group, 'ObjectPath');
|
||||
title = keyfile.get_locale_string(group, 'Title', null);
|
||||
|
||||
let appInfo = null;
|
||||
try {
|
||||
let desktopId = keyfile.get_string(group, 'DesktopId');
|
||||
appInfo = Gio.DesktopAppInfo.new(desktopId);
|
||||
} catch (e) {
|
||||
}
|
||||
|
||||
let icon;
|
||||
if (appInfo) {
|
||||
icon = appInfo.get_icon();
|
||||
title = appInfo.get_name();
|
||||
} else {
|
||||
let iconName = keyfile.get_string(group, 'Icon');
|
||||
icon = new Gio.ThemedIcon({ name: iconName });
|
||||
title = keyfile.get_locale_string(group, 'Title', null);
|
||||
}
|
||||
|
||||
remoteProvider = new RemoteSearchProvider(title,
|
||||
icon,
|
||||
|
@ -51,7 +51,7 @@ const SearchResultDisplay = new Lang.Class({
|
||||
* Remove all results from this display.
|
||||
*/
|
||||
clear: function() {
|
||||
this.actor.get_children().forEach(function (actor) { actor.destroy(); });
|
||||
this.actor.destroy_all_children();
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -7,6 +7,7 @@ const Shell = imports.gi.Shell;
|
||||
|
||||
const Config = imports.misc.config;
|
||||
const ExtensionSystem = imports.ui.extensionSystem;
|
||||
const ExtensionDownloader = imports.ui.extensionDownloader;
|
||||
const ExtensionUtils = imports.misc.extensionUtils;
|
||||
const Flashspot = imports.ui.flashspot;
|
||||
const Main = imports.ui.main;
|
||||
@ -66,6 +67,9 @@ const GnomeShellIface = <interface name="org.gnome.Shell">
|
||||
<method name="LaunchExtensionPrefs">
|
||||
<arg type="s" direction="in" name="uuid"/>
|
||||
</method>
|
||||
<method name="ReloadExtension">
|
||||
<arg type="s" direction="in" name="uuid"/>
|
||||
</method>
|
||||
<property name="OverviewActive" type="b" access="readwrite" />
|
||||
<property name="ApiVersion" type="i" access="read" />
|
||||
<property name="ShellVersion" type="s" access="read" />
|
||||
@ -254,11 +258,11 @@ const GnomeShell = new Lang.Class({
|
||||
},
|
||||
|
||||
InstallRemoteExtension: function(uuid) {
|
||||
ExtensionSystem.installExtensionFromUUID(uuid);
|
||||
ExtensionDownloader.installExtensionFromUUID(uuid);
|
||||
},
|
||||
|
||||
UninstallExtension: function(uuid) {
|
||||
return ExtensionSystem.uninstallExtensionFromUUID(uuid);
|
||||
return ExtensionDownloader.uninstallExtensionFromUUID(uuid);
|
||||
},
|
||||
|
||||
LaunchExtensionPrefs: function(uuid) {
|
||||
@ -268,6 +272,11 @@ const GnomeShell = new Lang.Class({
|
||||
['extension:///' + uuid], -1, null);
|
||||
},
|
||||
|
||||
ReloadExtension: function(uuid) {
|
||||
ExtensionSystem.unloadExtension(uuid);
|
||||
ExtensionSystem.loadExtension(uuid);
|
||||
},
|
||||
|
||||
get OverviewActive() {
|
||||
return Main.overview.visible;
|
||||
},
|
||||
@ -279,8 +288,6 @@ const GnomeShell = new Lang.Class({
|
||||
Main.overview.hide();
|
||||
},
|
||||
|
||||
ApiVersion: ExtensionSystem.API_VERSION,
|
||||
|
||||
ShellVersion: Config.PACKAGE_VERSION,
|
||||
|
||||
_extensionStateChanged: function(_, newState) {
|
||||
|
@ -1,17 +1,21 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Pango = imports.gi.Pango;
|
||||
const St = imports.gi.St;
|
||||
const Shell = imports.gi.Shell;
|
||||
|
||||
const CheckBox = imports.ui.checkBox;
|
||||
const Main = imports.ui.main;
|
||||
const MessageTray = imports.ui.messageTray;
|
||||
const ModalDialog = imports.ui.modalDialog;
|
||||
const Params = imports.misc.params;
|
||||
const ShellEntry = imports.ui.shellEntry;
|
||||
|
||||
const LIST_ITEM_ICON_SIZE = 48;
|
||||
|
||||
@ -48,6 +52,11 @@ function _setLabelsForMessage(dialog, message) {
|
||||
_setLabelText(dialog.descriptionLabel, labels[1]);
|
||||
}
|
||||
|
||||
function _createIcon(gicon) {
|
||||
return new St.Icon({ gicon: gicon,
|
||||
style_class: 'shell-mount-operation-icon' })
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------- */
|
||||
|
||||
const ListItem = new Lang.Class({
|
||||
@ -91,11 +100,11 @@ const ShellMountOperation = new Lang.Class({
|
||||
Name: 'ShellMountOperation',
|
||||
|
||||
_init: function(source, params) {
|
||||
params = Params.parse(params, { reaskPassword: false });
|
||||
|
||||
this._reaskPassword = params.reaskPassword;
|
||||
params = Params.parse(params, { existingDialog: null });
|
||||
|
||||
this._dialog = null;
|
||||
this._dialogId = 0;
|
||||
this._existingDialog = params.existingDialog;
|
||||
this._processesDialog = null;
|
||||
|
||||
this.mountOp = new Shell.MountOperation();
|
||||
@ -107,99 +116,120 @@ const ShellMountOperation = new Lang.Class({
|
||||
this.mountOp.connect('show-processes-2',
|
||||
Lang.bind(this, this._onShowProcesses2));
|
||||
this.mountOp.connect('aborted',
|
||||
Lang.bind(this, this._onAborted));
|
||||
Lang.bind(this, this.close));
|
||||
|
||||
this._icon = new St.Icon({ gicon: source.get_icon(),
|
||||
style_class: 'shell-mount-operation-icon' });
|
||||
this._gicon = source.get_icon();
|
||||
},
|
||||
|
||||
_closeExistingDialog: function() {
|
||||
if (!this._existingDialog)
|
||||
return;
|
||||
|
||||
this._existingDialog.close();
|
||||
this._existingDialog = null;
|
||||
},
|
||||
|
||||
_onAskQuestion: function(op, message, choices) {
|
||||
this._dialog = new ShellMountQuestionDialog(this._icon);
|
||||
this._closeExistingDialog();
|
||||
this._dialog = new ShellMountQuestionDialog(this._gicon);
|
||||
|
||||
this._dialog.connect('response',
|
||||
Lang.bind(this, function(object, choice) {
|
||||
this.mountOp.set_choice(choice);
|
||||
this.mountOp.reply(Gio.MountOperationResult.HANDLED);
|
||||
this._dialogId = 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.close();
|
||||
}));
|
||||
|
||||
this._dialog.update(message, choices);
|
||||
this._dialog.open(global.get_current_time());
|
||||
this._dialog.open();
|
||||
},
|
||||
|
||||
_onAskPassword: function(op, message) {
|
||||
this._notificationShowing = true;
|
||||
this._source = new ShellMountPasswordSource(message, this._icon, this._reaskPassword);
|
||||
_onAskPassword: function(op, message, defaultUser, defaultDomain, flags) {
|
||||
if (this._existingDialog) {
|
||||
this._dialog = this._existingDialog;
|
||||
this._dialog.reaskPassword();
|
||||
} else {
|
||||
this._dialog = new ShellMountPasswordDialog(message, this._gicon, flags);
|
||||
}
|
||||
|
||||
this._source.connect('password-ready',
|
||||
Lang.bind(this, function(source, password) {
|
||||
this.mountOp.set_password(password);
|
||||
this.mountOp.reply(Gio.MountOperationResult.HANDLED);
|
||||
this._dialogId = this._dialog.connect('response', Lang.bind(this,
|
||||
function(object, choice, password, remember) {
|
||||
if (choice == -1) {
|
||||
this.mountOp.reply(Gio.MountOperationResult.ABORTED);
|
||||
} else {
|
||||
if (remember)
|
||||
this.mountOp.set_password_save(Gio.PasswordSave.PERMANENTLY);
|
||||
else
|
||||
this.mountOp.set_password_save(Gio.PasswordSave.NEVER);
|
||||
|
||||
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);
|
||||
}));
|
||||
this.mountOp.set_password(password);
|
||||
this.mountOp.reply(Gio.MountOperationResult.HANDLED);
|
||||
}
|
||||
}));
|
||||
this._dialog.open();
|
||||
},
|
||||
|
||||
_onAborted: function(op) {
|
||||
if (!this._dialog)
|
||||
return;
|
||||
close: function(op) {
|
||||
this._closeExistingDialog();
|
||||
this._processesDialog = null;
|
||||
|
||||
this._dialog.close(global.get_current_time());
|
||||
this._dialog = null;
|
||||
if (this._dialog) {
|
||||
this._dialog.close();
|
||||
this._dialog = null;
|
||||
}
|
||||
},
|
||||
|
||||
_onShowProcesses2: function(op) {
|
||||
this._closeExistingDialog();
|
||||
|
||||
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._processesDialog = new ShellProcessesDialog(this._gicon);
|
||||
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._dialogId = 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.close();
|
||||
}));
|
||||
this._processesDialog.open();
|
||||
}
|
||||
|
||||
this._processesDialog.update(message, processes, choices);
|
||||
},
|
||||
|
||||
borrowDialog: function() {
|
||||
if (this._dialogId != 0) {
|
||||
this._dialog.disconnect(this._dialogId);
|
||||
this._dialogId = 0;
|
||||
}
|
||||
|
||||
return this._dialog;
|
||||
}
|
||||
});
|
||||
|
||||
const ShellMountQuestionDialog = new Lang.Class({
|
||||
Name: 'ShellMountQuestionDialog',
|
||||
Extends: ModalDialog.ModalDialog,
|
||||
|
||||
_init: function(icon) {
|
||||
_init: function(gicon) {
|
||||
this.parent({ 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 });
|
||||
this._iconBin = new St.Bin({ child: _createIcon(gicon) });
|
||||
mainContentLayout.add(this._iconBin,
|
||||
{ x_fill: true,
|
||||
y_fill: false,
|
||||
@ -234,63 +264,107 @@ const ShellMountQuestionDialog = new Lang.Class({
|
||||
});
|
||||
Signals.addSignalMethods(ShellMountQuestionDialog.prototype);
|
||||
|
||||
const ShellMountPasswordSource = new Lang.Class({
|
||||
Name: 'ShellMountPasswordSource',
|
||||
Extends: MessageTray.Source,
|
||||
const ShellMountPasswordDialog = new Lang.Class({
|
||||
Name: 'ShellMountPasswordDialog',
|
||||
Extends: ModalDialog.ModalDialog,
|
||||
|
||||
_init: function(message, icon, reaskPassword) {
|
||||
_init: function(message, gicon, flags) {
|
||||
let strings = message.split('\n');
|
||||
this.parent(strings[0]);
|
||||
this.parent({ styleClass: 'prompt-dialog' });
|
||||
|
||||
this._notification = new ShellMountPasswordNotification(this, strings, icon, reaskPassword);
|
||||
this._setSummaryIcon(icon);
|
||||
let mainContentBox = new St.BoxLayout({ style_class: 'prompt-dialog-main-layout',
|
||||
vertical: false });
|
||||
this.contentLayout.add(mainContentBox);
|
||||
|
||||
// add ourselves as a source, and popup the notification
|
||||
Main.messageTray.add(this);
|
||||
this.notify(this._notification);
|
||||
},
|
||||
});
|
||||
Signals.addSignalMethods(ShellMountPasswordSource.prototype);
|
||||
let icon = _createIcon(gicon);
|
||||
mainContentBox.add(icon,
|
||||
{ x_fill: true,
|
||||
y_fill: false,
|
||||
x_align: St.Align.END,
|
||||
y_align: St.Align.START });
|
||||
|
||||
const ShellMountPasswordNotification = new Lang.Class({
|
||||
Name: 'ShellMountPasswordNotification',
|
||||
Extends: MessageTray.Notification,
|
||||
this._messageBox = new St.BoxLayout({ style_class: 'prompt-dialog-message-layout',
|
||||
vertical: true });
|
||||
mainContentBox.add(this._messageBox,
|
||||
{ y_align: St.Align.START, expand: true, x_fill: true, y_fill: true });
|
||||
|
||||
_init: function(source, strings, icon, reaskPassword) {
|
||||
this.parent(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);
|
||||
let subject = new St.Label({ style_class: 'prompt-dialog-headline' });
|
||||
this._messageBox.add(subject,
|
||||
{ y_fill: false,
|
||||
y_align: St.Align.START });
|
||||
if (strings[0])
|
||||
subject.set_text(strings[0]);
|
||||
|
||||
let description = new St.Label({ style_class: 'prompt-dialog-description' });
|
||||
description.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||
description.clutter_text.line_wrap = true;
|
||||
this._messageBox.add(description,
|
||||
{ y_fill: true,
|
||||
y_align: St.Align.START });
|
||||
if (strings[1])
|
||||
this.addBody(strings[1]);
|
||||
description.set_text(strings[1]);
|
||||
|
||||
if (reaskPassword) {
|
||||
let label = new St.Label({ style_class: 'mount-password-reask',
|
||||
text: _("Wrong password, please try again") });
|
||||
this._passwordBox = new St.BoxLayout({ vertical: false });
|
||||
this._messageBox.add(this._passwordBox);
|
||||
|
||||
this.addActor(label);
|
||||
this._passwordLabel = new St.Label(({ style_class: 'prompt-dialog-password-label',
|
||||
text: _("Passphrase") }));
|
||||
this._passwordBox.add(this._passwordLabel);
|
||||
|
||||
this._passwordEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
|
||||
text: "",
|
||||
can_focus: true});
|
||||
ShellEntry.addContextMenu(this._passwordEntry, { isPassword: true });
|
||||
this._passwordEntry.clutter_text.connect('activate', Lang.bind(this, this._onEntryActivate));
|
||||
this._passwordEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
|
||||
this._passwordBox.add(this._passwordEntry, {expand: true });
|
||||
this.setInitialKeyFocus(this._passwordEntry);
|
||||
|
||||
this._errorMessageLabel = new St.Label({ style_class: 'prompt-dialog-error-label',
|
||||
text: _("Sorry, that didn\'t work. Please try again.") });
|
||||
this._errorMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||
this._errorMessageLabel.clutter_text.line_wrap = true;
|
||||
this._errorMessageLabel.hide();
|
||||
this._messageBox.add(this._errorMessageLabel);
|
||||
|
||||
if (flags & Gio.AskPasswordFlags.SAVING_SUPPORTED) {
|
||||
this._rememberChoice = new CheckBox.CheckBox();
|
||||
this._rememberChoice.getLabelActor().text = _("Remember Passphrase");
|
||||
this._rememberChoice.actor.checked = true;
|
||||
this._messageBox.add(this._rememberChoice.actor);
|
||||
} else {
|
||||
this._rememberChoice = null;
|
||||
}
|
||||
|
||||
this._responseEntry = new St.Entry({ style_class: 'mount-password-entry',
|
||||
can_focus: true });
|
||||
this.setActionArea(this._responseEntry);
|
||||
let buttons = [{ label: _("Cancel"),
|
||||
action: Lang.bind(this, this._onCancelButton),
|
||||
key: Clutter.Escape
|
||||
},
|
||||
{ label: _("Unlock"),
|
||||
action: Lang.bind(this, this._onUnlockButton)
|
||||
}];
|
||||
|
||||
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();
|
||||
this.setButtons(buttons);
|
||||
},
|
||||
|
||||
_onEntryActivated: function() {
|
||||
let text = this._responseEntry.get_text();
|
||||
if (text == '')
|
||||
return;
|
||||
reaskPassword: function() {
|
||||
this._passwordEntry.set_text('');
|
||||
this._errorMessageLabel.show();
|
||||
},
|
||||
|
||||
this.source.emit('password-ready', text);
|
||||
_onCancelButton: function() {
|
||||
this.emit('response', -1, '', false);
|
||||
},
|
||||
|
||||
_onUnlockButton: function() {
|
||||
this._onEntryActivate();
|
||||
},
|
||||
|
||||
_onEntryActivate: function() {
|
||||
this.emit('response', 1,
|
||||
this._passwordEntry.get_text(),
|
||||
this._rememberChoice &&
|
||||
this._rememberChoice.actor.checked);
|
||||
}
|
||||
});
|
||||
|
||||
@ -298,14 +372,14 @@ const ShellProcessesDialog = new Lang.Class({
|
||||
Name: 'ShellProcessesDialog',
|
||||
Extends: ModalDialog.ModalDialog,
|
||||
|
||||
_init: function(icon) {
|
||||
_init: function(gicon) {
|
||||
this.parent({ 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 });
|
||||
this._iconBin = new St.Bin({ child: _createIcon(gicon) });
|
||||
mainContentLayout.add(this._iconBin,
|
||||
{ x_fill: true,
|
||||
y_fill: false,
|
||||
@ -347,13 +421,13 @@ const ShellProcessesDialog = new Lang.Class({
|
||||
|
||||
this._applicationList.connect('actor-added',
|
||||
Lang.bind(this, function() {
|
||||
if (this._applicationList.get_children().length == 1)
|
||||
if (this._applicationList.get_n_children() == 1)
|
||||
scrollView.show();
|
||||
}));
|
||||
|
||||
this._applicationList.connect('actor-removed',
|
||||
Lang.bind(this, function() {
|
||||
if (this._applicationList.get_children().length == 0)
|
||||
if (this._applicationList.get_n_children() == 0)
|
||||
scrollView.hide();
|
||||
}));
|
||||
},
|
||||
@ -387,3 +461,253 @@ const ShellProcessesDialog = new Lang.Class({
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(ShellProcessesDialog.prototype);
|
||||
|
||||
const GnomeShellMountOpIface = <interface name="org.Gtk.MountOperationHandler">
|
||||
<method name="AskPassword">
|
||||
<arg type="s" direction="in" name="object_id"/>
|
||||
<arg type="s" direction="in" name="message"/>
|
||||
<arg type="s" direction="in" name="icon_name"/>
|
||||
<arg type="s" direction="in" name="default_user"/>
|
||||
<arg type="s" direction="in" name="default_domain"/>
|
||||
<arg type="u" direction="in" name="flags"/>
|
||||
<arg type="u" direction="out" name="response"/>
|
||||
<arg type="a{sv}" direction="out" name="response_details"/>
|
||||
</method>
|
||||
<method name="AskQuestion">
|
||||
<arg type="s" direction="in" name="object_id"/>
|
||||
<arg type="s" direction="in" name="message"/>
|
||||
<arg type="s" direction="in" name="icon_name"/>
|
||||
<arg type="as" direction="in" name="choices"/>
|
||||
<arg type="u" direction="out" name="response"/>
|
||||
<arg type="a{sv}" direction="out" name="response_details"/>
|
||||
</method>
|
||||
<method name="ShowProcesses">
|
||||
<arg type="s" direction="in" name="object_id"/>
|
||||
<arg type="s" direction="in" name="message"/>
|
||||
<arg type="s" direction="in" name="icon_name"/>
|
||||
<arg type="ai" direction="in" name="application_pids"/>
|
||||
<arg type="as" direction="in" name="choices"/>
|
||||
<arg type="u" direction="out" name="response"/>
|
||||
<arg type="a{sv}" direction="out" name="response_details"/>
|
||||
</method>
|
||||
<method name="Close"/>
|
||||
</interface>;
|
||||
|
||||
const ShellMountOperationType = {
|
||||
NONE: 0,
|
||||
ASK_PASSWORD: 1,
|
||||
ASK_QUESTION: 2,
|
||||
SHOW_PROCESSES: 3
|
||||
};
|
||||
|
||||
const GnomeShellMountOpHandler = new Lang.Class({
|
||||
Name: 'GnomeShellMountOpHandler',
|
||||
|
||||
_init: function() {
|
||||
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(GnomeShellMountOpIface, this);
|
||||
this._dbusImpl.export(Gio.DBus.session, '/org/gtk/MountOperationHandler');
|
||||
Gio.bus_own_name_on_connection(Gio.DBus.session, 'org.gtk.MountOperationHandler',
|
||||
Gio.BusNameOwnerFlags.REPLACE, null, null);
|
||||
|
||||
this._dialog = null;
|
||||
this._volumeMonitor = Gio.VolumeMonitor.get();
|
||||
|
||||
this._ensureEmptyRequest();
|
||||
},
|
||||
|
||||
_ensureEmptyRequest: function() {
|
||||
this._currentId = null;
|
||||
this._currentInvocation = null;
|
||||
this._currentType = ShellMountOperationType.NONE;
|
||||
},
|
||||
|
||||
_clearCurrentRequest: function(response, details) {
|
||||
if (this._currentInvocation) {
|
||||
this._currentInvocation.return_value(
|
||||
GLib.Variant.new('(ua{sv})', [response, details]));
|
||||
}
|
||||
|
||||
this._ensureEmptyRequest();
|
||||
},
|
||||
|
||||
_setCurrentRequest: function(invocation, id, type) {
|
||||
let oldId = this._currentId;
|
||||
let oldType = this._currentType;
|
||||
let requestId = id + '@' + invocation.get_sender();
|
||||
|
||||
this._clearCurrentRequest(Gio.MountOperationResult.UNHANDLED, {});
|
||||
|
||||
this._currentInvocation = invocation;
|
||||
this._currentId = requestId;
|
||||
this._currentType = type;
|
||||
|
||||
if (this._dialog && (oldId == requestId) && (oldType == type))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
_closeDialog: function() {
|
||||
if (this._dialog) {
|
||||
this._dialog.close();
|
||||
this._dialog = null;
|
||||
}
|
||||
},
|
||||
|
||||
_createGIcon: function(iconName) {
|
||||
let realIconName = iconName ? iconName : 'drive-harddisk';
|
||||
return new Gio.ThemedIcon({ name: realIconName,
|
||||
use_default_fallbacks: true });
|
||||
},
|
||||
|
||||
/**
|
||||
* AskPassword:
|
||||
* @id: an opaque ID identifying the object for which the operation is requested
|
||||
* The ID must be unique in the context of the calling process.
|
||||
* @message: the message to display
|
||||
* @icon_name: the name of an icon to display
|
||||
* @default_user: the default username for display
|
||||
* @default_domain: the default domain for display
|
||||
* @flags: a set of GAskPasswordFlags
|
||||
* @response: a GMountOperationResult
|
||||
* @response_details: a dictionary containing the response details as
|
||||
* entered by the user. The dictionary MAY contain the following properties:
|
||||
* - "password" -> (s): a password to be used to complete the mount operation
|
||||
* - "password_save" -> (u): a GPasswordSave
|
||||
*
|
||||
* The dialog will stay visible until clients call the Close() method, or
|
||||
* another dialog becomes visible.
|
||||
* Calling AskPassword again for the same id will have the effect to clear
|
||||
* the existing dialog and update it with a message indicating the previous
|
||||
* attempt went wrong.
|
||||
*/
|
||||
AskPasswordAsync: function(params, invocation) {
|
||||
let [id, message, iconName, defaultUser, defaultDomain, flags] = params;
|
||||
|
||||
if (this._setCurrentRequest(invocation, id, ShellMountOperationType.ASK_PASSWORD)) {
|
||||
this._dialog.reaskPassword();
|
||||
return;
|
||||
}
|
||||
|
||||
this._closeDialog();
|
||||
|
||||
this._dialog = new ShellMountPasswordDialog(message, this._createGIcon(iconName), flags);
|
||||
this._dialog.connect('response', Lang.bind(this,
|
||||
function(object, choice, password, remember) {
|
||||
let details = {};
|
||||
let response;
|
||||
|
||||
if (choice == -1) {
|
||||
response = Gio.MountOperationResult.ABORTED;
|
||||
} else {
|
||||
response = Gio.MountOperationResult.HANDLED;
|
||||
|
||||
let passSave = remember ? Gio.PasswordSave.PERMANENTLY : Gio.PasswordSave.NEVER;
|
||||
details['password_save'] = GLib.Variant.new('u', passSave);
|
||||
details['password'] = GLib.Variant.new('s', password);
|
||||
}
|
||||
|
||||
this._clearCurrentRequest(response, details);
|
||||
}));
|
||||
this._dialog.open();
|
||||
},
|
||||
|
||||
/**
|
||||
* AskQuestion:
|
||||
* @id: an opaque ID identifying the object for which the operation is requested
|
||||
* The ID must be unique in the context of the calling process.
|
||||
* @message: the message to display
|
||||
* @icon_name: the name of an icon to display
|
||||
* @choices: an array of choice strings
|
||||
* GetResponse:
|
||||
* @response: a GMountOperationResult
|
||||
* @response_details: a dictionary containing the response details as
|
||||
* entered by the user. The dictionary MAY contain the following properties:
|
||||
* - "choice" -> (i): the chosen answer among the array of strings passed in
|
||||
*
|
||||
* The dialog will stay visible until clients call the Close() method, or
|
||||
* another dialog becomes visible.
|
||||
* Calling AskQuestion again for the same id will have the effect to clear
|
||||
* update the dialog with the new question.
|
||||
*/
|
||||
AskQuestionAsync: function(params, invocation) {
|
||||
let [id, message, iconName, choices] = params;
|
||||
|
||||
if (this._setCurrentRequest(invocation, id, ShellMountOperationType.ASK_QUESTION)) {
|
||||
this._dialog.update(message, choices);
|
||||
return;
|
||||
}
|
||||
|
||||
this._closeDialog();
|
||||
|
||||
this._dialog = new ShellMountQuestionDialog(this._createGIcon(iconName), message);
|
||||
this._dialog.connect('response', Lang.bind(this,
|
||||
function(object, choice) {
|
||||
this._clearCurrentRequest(Gio.MountOperationResult.HANDLED,
|
||||
{ choice: GLib.Variant.new('i', choice) });
|
||||
}));
|
||||
|
||||
this._dialog.update(message, choices);
|
||||
this._dialog.open();
|
||||
},
|
||||
|
||||
/**
|
||||
* ShowProcesses:
|
||||
* @id: an opaque ID identifying the object for which the operation is requested
|
||||
* The ID must be unique in the context of the calling process.
|
||||
* @message: the message to display
|
||||
* @icon_name: the name of an icon to display
|
||||
* @application_pids: the PIDs of the applications to display
|
||||
* @choices: an array of choice strings
|
||||
* @response: a GMountOperationResult
|
||||
* @response_details: a dictionary containing the response details as
|
||||
* entered by the user. The dictionary MAY contain the following properties:
|
||||
* - "choice" -> (i): the chosen answer among the array of strings passed in
|
||||
*
|
||||
* The dialog will stay visible until clients call the Close() method, or
|
||||
* another dialog becomes visible.
|
||||
* Calling ShowProcesses again for the same id will have the effect to clear
|
||||
* the existing dialog and update it with the new message and the new list
|
||||
* of processes.
|
||||
*/
|
||||
ShowProcessesAsync: function(params, invocation) {
|
||||
let [id, message, iconName, applicationPids, choices] = params;
|
||||
|
||||
if (this._setCurrentRequest(invocation, id, ShellMountOperationType.SHOW_PROCESSES)) {
|
||||
this._dialog.update(message, applicationPids, choices);
|
||||
return;
|
||||
}
|
||||
|
||||
this._closeDialog();
|
||||
|
||||
this._dialog = new ShellProcessesDialog(this._createGIcon(iconName));
|
||||
this._dialog.connect('response', Lang.bind(this,
|
||||
function(object, choice) {
|
||||
let response;
|
||||
let details = {};
|
||||
|
||||
if (choice == -1) {
|
||||
response = Gio.MountOperationResult.ABORTED;
|
||||
} else {
|
||||
response = Gio.MountOperationResult.HANDLED;
|
||||
details['choice'] = GLib.Variant.new('i', choice);
|
||||
}
|
||||
|
||||
this._clearCurrentRequest(response, details);
|
||||
}));
|
||||
|
||||
this._dialog.update(message, applicationPids, choices);
|
||||
this._dialog.open();
|
||||
},
|
||||
|
||||
/**
|
||||
* Close:
|
||||
*
|
||||
* Closes a dialog previously opened by AskPassword, AskQuestion or ShowProcesses.
|
||||
* If no dialog is open, does nothing.
|
||||
*/
|
||||
Close: function(params, invocation) {
|
||||
this._clearCurrentRequest(Gio.MountOperationResult.UNHANDLED, {});
|
||||
this._closeDialog();
|
||||
}
|
||||
});
|
||||
|
@ -56,9 +56,9 @@ const ATIndicator = new Lang.Class({
|
||||
let textZoom = this._buildFontItem();
|
||||
this.menu.addMenuItem(textZoom);
|
||||
|
||||
// let screenReader = this._buildItem(_("Screen Reader"), APPLICATIONS_SCHEMA,
|
||||
// 'screen-reader-enabled');
|
||||
// this.menu.addMenuItem(screenReader);
|
||||
let screenReader = this._buildItem(_("Screen Reader"), APPLICATIONS_SCHEMA,
|
||||
'screen-reader-enabled');
|
||||
this.menu.addMenuItem(screenReader);
|
||||
|
||||
let screenKeyboard = this._buildItem(_("Screen Keyboard"), APPLICATIONS_SCHEMA,
|
||||
'screen-keyboard-enabled');
|
||||
|
@ -101,11 +101,10 @@ const NMNetworkMenuItem = new Lang.Class({
|
||||
Name: 'NMNetworkMenuItem',
|
||||
Extends: PopupMenu.PopupBaseMenuItem,
|
||||
|
||||
_init: function(accessPoints, title, params) {
|
||||
_init: function(bestAP, title, params) {
|
||||
this.parent(params);
|
||||
|
||||
accessPoints = sortAccessPoints(accessPoints);
|
||||
this.bestAP = accessPoints[0];
|
||||
this.bestAP = bestAP;
|
||||
|
||||
if (!title) {
|
||||
let ssid = this.bestAP.get_ssid();
|
||||
@ -127,24 +126,10 @@ const NMNetworkMenuItem = new Lang.Class({
|
||||
this.bestAP._secType != NMAccessPointSecurity.NONE)
|
||||
this._secureIcon.icon_name = 'network-wireless-encrypted';
|
||||
this._icons.add_actor(this._secureIcon);
|
||||
|
||||
this._accessPoints = [ ];
|
||||
for (let i = 0; i < accessPoints.length; i++) {
|
||||
let ap = accessPoints[i];
|
||||
// need a wrapper object here, because the access points can be shared
|
||||
// between many NMNetworkMenuItems
|
||||
let apObj = {
|
||||
ap: ap,
|
||||
updateId: ap.connect('notify::strength', Lang.bind(this, this._updated))
|
||||
};
|
||||
this._accessPoints.push(apObj);
|
||||
}
|
||||
},
|
||||
|
||||
_updated: function(ap) {
|
||||
if (ap.strength > this.bestAP.strength)
|
||||
this.bestAP = ap;
|
||||
|
||||
updateBestAP: function(ap) {
|
||||
this.bestAP = ap;
|
||||
this._signalIcon.icon_name = this._getIcon();
|
||||
},
|
||||
|
||||
@ -153,36 +138,6 @@ const NMNetworkMenuItem = new Lang.Class({
|
||||
return 'network-workgroup';
|
||||
else
|
||||
return 'network-wireless-signal-' + signalToIcon(this.bestAP.strength);
|
||||
},
|
||||
|
||||
updateAccessPoints: function(accessPoints) {
|
||||
for (let i = 0; i < this._accessPoints.length; i++) {
|
||||
let apObj = this._accessPoints[i];
|
||||
apObj.ap.disconnect(apObj.updateId);
|
||||
apObj.updateId = 0;
|
||||
}
|
||||
|
||||
accessPoints = sortAccessPoints(accessPoints);
|
||||
this.bestAP = accessPoints[0];
|
||||
this._accessPoints = [ ];
|
||||
for (let i = 0; i < accessPoints; i++) {
|
||||
let ap = accessPoints[i];
|
||||
let apObj = {
|
||||
ap: ap,
|
||||
updateId: ap.connect('notify::strength', Lang.bind(this, this._updated))
|
||||
};
|
||||
this._accessPoints.push(apObj);
|
||||
}
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
for (let i = 0; i < this._accessPoints.length; i++) {
|
||||
let apObj = this._accessPoints[i];
|
||||
apObj.ap.disconnect(apObj.updateId);
|
||||
apObj.updateId = 0;
|
||||
}
|
||||
|
||||
this.parent();
|
||||
}
|
||||
});
|
||||
|
||||
@ -297,7 +252,7 @@ const NMDevice = new Lang.Class({
|
||||
this._client = client;
|
||||
this._connections = [ ];
|
||||
for (let i = 0; i < connections.length; i++) {
|
||||
if (!connections[i]._uuid)
|
||||
if (!connections[i].get_uuid())
|
||||
continue;
|
||||
if (!this.connectionValid(connections[i]))
|
||||
continue;
|
||||
@ -613,7 +568,7 @@ const NMDevice = new Lang.Class({
|
||||
let title;
|
||||
let active = this._activeConnection._connection;
|
||||
if (active) {
|
||||
title = active._name;
|
||||
title = active.get_id();
|
||||
} else {
|
||||
/* TRANSLATORS: this is the indication that a connection for another logged in user is active,
|
||||
and we cannot access its settings (including the name) */
|
||||
@ -1026,6 +981,7 @@ const NMDeviceWireless = new Lang.Class({
|
||||
obj.ssidText = ssidToLabel(obj.ssid);
|
||||
this._networks.push(obj);
|
||||
}
|
||||
ap._updateId = ap.connect('notify::strength', Lang.bind(this, this._onApStrengthChanged));
|
||||
|
||||
// Check if some connection is valid for this AP
|
||||
for (let j = 0; j < validConnections.length; j++) {
|
||||
@ -1037,6 +993,10 @@ const NMDeviceWireless = new Lang.Class({
|
||||
}
|
||||
}
|
||||
|
||||
// Sort APs within each network by strength
|
||||
for (let i = 0; i < this._networks.length; i++)
|
||||
sortAccessPoints(this._networks[i].accessPoints);
|
||||
|
||||
if (this.device.active_access_point) {
|
||||
let networkPos = this._findNetwork(this.device.active_access_point);
|
||||
|
||||
@ -1119,7 +1079,7 @@ const NMDeviceWireless = new Lang.Class({
|
||||
// the user toggles the switch and has more than one wireless device)
|
||||
if (this._networks.length > 0) {
|
||||
let connection = this._createAutomaticConnection(this._networks[0]);
|
||||
let accessPoints = sortAccessPoints(this._networks[0].accessPoints);
|
||||
let accessPoints = this._networks[0].accessPoints;
|
||||
this._client.add_and_activate_connection(connection, this.device, accessPoints[0].dbus_path, null);
|
||||
}
|
||||
},
|
||||
@ -1189,6 +1149,13 @@ const NMDeviceWireless = new Lang.Class({
|
||||
else if (!oneHasConnection && twoHasConnection)
|
||||
return 1;
|
||||
|
||||
let oneStrength = one.accessPoints[0].strength;
|
||||
let twoStrength = two.accessPoints[0].strength;
|
||||
|
||||
// place stronger connections first
|
||||
if (oneStrength != twoStrength)
|
||||
return oneStrength < twoStrength ? 1 : -1;
|
||||
|
||||
let oneHasSecurity = one.security != NMAccessPointSecurity.NONE;
|
||||
let twoHasSecurity = two.security != NMAccessPointSecurity.NONE;
|
||||
|
||||
@ -1238,6 +1205,28 @@ const NMDeviceWireless = new Lang.Class({
|
||||
return -1;
|
||||
},
|
||||
|
||||
_onApStrengthChanged: function(ap) {
|
||||
let res = this._findExistingNetwork(ap);
|
||||
if (res == null) {
|
||||
// Uhm... stale signal?
|
||||
return;
|
||||
}
|
||||
|
||||
let network = this._networks[res.network];
|
||||
network.accessPoints.splice(res.ap, 1);
|
||||
Util.insertSorted(network.accessPoints, ap, function(one, two) {
|
||||
return two.strength - one.strength;
|
||||
});
|
||||
|
||||
this._networks.splice(res.network, 1);
|
||||
let newPos = Util.insertSorted(this._networks, network, Lang.bind(this, this._networkSortFunction));
|
||||
|
||||
if (newPos != res.network) {
|
||||
this._clearSection();
|
||||
this._queueCreateSection();
|
||||
}
|
||||
},
|
||||
|
||||
_accessPointAdded: function(device, accessPoint) {
|
||||
if (accessPoint.get_ssid() == null) {
|
||||
// This access point is not visible yet
|
||||
@ -1257,9 +1246,11 @@ const NMDeviceWireless = new Lang.Class({
|
||||
return;
|
||||
}
|
||||
|
||||
apObj.accessPoints.push(accessPoint);
|
||||
Util.insertSorted(apObj.accessPoints, accessPoint, function(one, two) {
|
||||
return two.strength - one.strength;
|
||||
});
|
||||
if (apObj.item)
|
||||
apObj.item.updateAccessPoints(apObj.accessPoints);
|
||||
apObj.item.updateBestAP(apObj.accessPoints[0]);
|
||||
} else {
|
||||
apObj = { ssid: accessPoint.get_ssid(),
|
||||
mode: accessPoint.mode,
|
||||
@ -1270,6 +1261,7 @@ const NMDeviceWireless = new Lang.Class({
|
||||
};
|
||||
apObj.ssidText = ssidToLabel(apObj.ssid);
|
||||
}
|
||||
accessPoint._updateId = accessPoint.connect('notify::strength', Lang.bind(this, this._onApStrengthChanged));
|
||||
|
||||
// check if this enables new connections for this group
|
||||
for (let i = 0; i < this._connections.length; i++) {
|
||||
@ -1277,23 +1269,26 @@ const NMDeviceWireless = new Lang.Class({
|
||||
if (accessPoint.connection_valid(connection) &&
|
||||
apObj.connections.indexOf(connection) == -1) {
|
||||
apObj.connections.push(connection);
|
||||
|
||||
// this potentially changes the order
|
||||
needsupdate = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos == -1 || needsupdate) {
|
||||
if (pos != -1)
|
||||
this._networks.splice(pos, 1);
|
||||
pos = Util.insertSorted(this._networks, apObj, this._networkSortFunction);
|
||||
if (pos != -1)
|
||||
this._networks.splice(pos, 1);
|
||||
let newPos = Util.insertSorted(this._networks, apObj, this._networkSortFunction);
|
||||
|
||||
// Queue an update of the UI if we changed the order
|
||||
if (newPos != pos) {
|
||||
this._clearSection();
|
||||
this._queueCreateSection();
|
||||
}
|
||||
},
|
||||
|
||||
_accessPointRemoved: function(device, accessPoint) {
|
||||
if (accessPoint._updateId) {
|
||||
accessPoint.disconnect(accessPoint._updateId);
|
||||
accessPoint._updateId = 0;
|
||||
}
|
||||
|
||||
let res = this._findExistingNetwork(accessPoint);
|
||||
|
||||
if (res == null) {
|
||||
@ -1335,17 +1330,30 @@ const NMDeviceWireless = new Lang.Class({
|
||||
this._overflowItem = null;
|
||||
}
|
||||
}
|
||||
this._networks.splice(res.network, 1);
|
||||
|
||||
} else if (apObj.item)
|
||||
apObj.item.updateAccessPoints(apObj.accessPoints);
|
||||
this._networks.splice(res.network, 1);
|
||||
} else {
|
||||
let okPrev = true, okNext = true;
|
||||
|
||||
if (res.network > 0)
|
||||
okPrev = this._networkSortFunction(this._networks[res.network - 1], apObj) >= 0;
|
||||
if (res.network < this._networks.length-1)
|
||||
okNext = this._networkSortFunction(this._networks[res.network + 1], apObj) <= 0;
|
||||
|
||||
if (!okPrev || !okNext) {
|
||||
this._clearSection();
|
||||
this._queueCreateSection();
|
||||
} else if (apObj.item) {
|
||||
apObj.item.updateBestAP(apObj.accessPoints[0]);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_createAPItem: function(connection, accessPointObj, useConnectionName) {
|
||||
let item = new NMNetworkMenuItem(accessPointObj.accessPoints, useConnectionName ? connection._name : undefined);
|
||||
let item = new NMNetworkMenuItem(accessPointObj.accessPoints[0], useConnectionName ? connection.get_id() : undefined);
|
||||
item._connection = connection;
|
||||
item.connect('activate', Lang.bind(this, function() {
|
||||
let accessPoints = sortAccessPoints(accessPointObj.accessPoints);
|
||||
let accessPoints = accessPointObj.accessPoints;
|
||||
for (let i = 0; i < accessPoints.length; i++) {
|
||||
if (accessPoints[i].connection_valid(connection)) {
|
||||
this._client.activate_connection(connection, this.device, accessPoints[i].dbus_path, null);
|
||||
@ -1452,27 +1460,19 @@ const NMDeviceWireless = new Lang.Class({
|
||||
},
|
||||
|
||||
_createActiveConnectionItem: function() {
|
||||
let icon, title;
|
||||
if (this._activeConnection && this._activeConnection._connection) {
|
||||
let connection = this._activeConnection._connection;
|
||||
if (this._activeNetwork)
|
||||
this._activeConnectionItem = new NMNetworkMenuItem(this._activeNetwork.accessPoints, undefined,
|
||||
{ reactive: false });
|
||||
else
|
||||
this._activeConnectionItem = new PopupMenu.PopupImageMenuItem(connection._name,
|
||||
'network-wireless-connected',
|
||||
{ reactive: false });
|
||||
} else {
|
||||
// We cannot read the connection (due to ACL, or API incompatibility), but we still show signal if we have it
|
||||
let menuItem;
|
||||
if (this._activeNetwork)
|
||||
this._activeConnectionItem = new NMNetworkMenuItem(this._activeNetwork.accessPoints, undefined,
|
||||
{ reactive: false });
|
||||
else
|
||||
this._activeConnectionItem = new PopupMenu.PopupImageMenuItem(_("Connected (private)"),
|
||||
'network-wireless-connected',
|
||||
{ reactive: false });
|
||||
}
|
||||
let title;
|
||||
if (this._activeConnection && this._activeConnection._connection)
|
||||
title = this._activeConnection._connection.get_id();
|
||||
else
|
||||
title = _("Connected (private)");
|
||||
|
||||
if (this._activeNetwork)
|
||||
this._activeConnectionItem = new NMNetworkMenuItem(this.device.active_access_point, undefined,
|
||||
{ reactive: false });
|
||||
else
|
||||
this._activeConnectionItem = new PopupMenu.PopupImageMenuItem(title,
|
||||
'network-wireless-connected',
|
||||
{ reactive: false });
|
||||
this._activeConnectionItem.setShowDot(true);
|
||||
},
|
||||
|
||||
@ -1512,9 +1512,9 @@ const NMDeviceWireless = new Lang.Class({
|
||||
apObj.item.menu.addMenuItem(this._createAPItem(apObj.connections[i], apObj, true));
|
||||
}
|
||||
} else {
|
||||
apObj.item = new NMNetworkMenuItem(apObj.accessPoints);
|
||||
apObj.item = new NMNetworkMenuItem(apObj.accessPoints[0]);
|
||||
apObj.item.connect('activate', Lang.bind(this, function() {
|
||||
let accessPoints = sortAccessPoints(apObj.accessPoints);
|
||||
let accessPoints = apObj.accessPoints;
|
||||
if ( (accessPoints[0]._secType == NMAccessPointSecurity.WPA2_ENT)
|
||||
|| (accessPoints[0]._secType == NMAccessPointSecurity.WPA_ENT)) {
|
||||
// 802.1x-enabled APs require further configuration, so they're
|
||||
@ -1567,10 +1567,25 @@ const NMDeviceWireless = new Lang.Class({
|
||||
|
||||
const NMApplet = new Lang.Class({
|
||||
Name: 'NMApplet',
|
||||
Extends: PanelMenu.SystemStatusButton,
|
||||
Extends: PanelMenu.Button,
|
||||
|
||||
_init: function() {
|
||||
this.parent('network-offline', _("Network"));
|
||||
this.parent(0.0, _('Network'));
|
||||
|
||||
this._box = new St.BoxLayout({ name: 'networkMenu' });
|
||||
this.actor.add_actor (this._box);
|
||||
this.actor.add_style_class_name('panel-status-button');
|
||||
|
||||
this._primaryIcon = new St.Icon({ icon_name: 'network-offline',
|
||||
icon_type: St.IconType.SYMBOLIC,
|
||||
style_class: 'system-status-icon' });
|
||||
this._box.add_actor(this._primaryIcon);
|
||||
|
||||
this._secondaryIcon = new St.Icon({ icon_name: 'network-vpn',
|
||||
icon_type: St.IconType.SYMBOLIC,
|
||||
style_class: 'system-status-icon',
|
||||
visible: false });
|
||||
this._box.add_actor(this._secondaryIcon);
|
||||
|
||||
this._client = NMClient.Client.new();
|
||||
|
||||
@ -1588,6 +1603,7 @@ const NMApplet = new Lang.Class({
|
||||
this._connections = [ ];
|
||||
|
||||
this._mainConnection = null;
|
||||
this._vpnConnection = null;
|
||||
this._activeAccessPointUpdateId = 0;
|
||||
this._activeAccessPoint = null;
|
||||
this._mobileUpdateId = 0;
|
||||
@ -1678,6 +1694,10 @@ const NMApplet = new Lang.Class({
|
||||
}));
|
||||
},
|
||||
|
||||
setIcon: function(iconName) {
|
||||
this._primaryIcon.icon_name = iconName;
|
||||
},
|
||||
|
||||
_ensureSource: function() {
|
||||
if (!this._source) {
|
||||
this._source = new MessageTray.Source(_("Network Manager"),
|
||||
@ -1851,6 +1871,8 @@ const NMApplet = new Lang.Class({
|
||||
|
||||
this._activeConnections = newActiveConnections;
|
||||
this._mainConnection = null;
|
||||
this._vpnConnection = null;
|
||||
|
||||
let activating = null;
|
||||
let default_ip4 = null;
|
||||
let default_ip6 = null;
|
||||
@ -1884,10 +1906,10 @@ const NMApplet = new Lang.Class({
|
||||
default_ip4 = a;
|
||||
if (a.default6)
|
||||
default_ip6 = a;
|
||||
|
||||
if (a._type == 'vpn')
|
||||
active_vpn = a;
|
||||
|
||||
if (a.state == NetworkManager.ActiveConnectionState.ACTIVATING)
|
||||
else if (a.state == NetworkManager.ActiveConnectionState.ACTIVATING)
|
||||
activating = a;
|
||||
|
||||
if (!a._primaryDevice) {
|
||||
@ -1916,7 +1938,8 @@ const NMApplet = new Lang.Class({
|
||||
}
|
||||
}
|
||||
|
||||
this._mainConnection = activating || active_vpn || default_ip4 || default_ip6 || this._activeConnections[0] || null;
|
||||
this._mainConnection = activating || default_ip4 || default_ip6 || this._activeConnections[0] || null;
|
||||
this._vpnConnection = active_vpn;
|
||||
},
|
||||
|
||||
_notifyActivated: function(activeConnection) {
|
||||
@ -2062,9 +2085,6 @@ const NMApplet = new Lang.Class({
|
||||
case NMConnectionCategory.WIRED:
|
||||
this.setIcon('network-wired-acquiring');
|
||||
break;
|
||||
case NMConnectionCategory.VPN:
|
||||
this.setIcon('network-vpn-acquiring');
|
||||
break;
|
||||
default:
|
||||
// fallback to a generic connected icon
|
||||
// (it could be a private connection of some other user)
|
||||
@ -2127,9 +2147,6 @@ const NMApplet = new Lang.Class({
|
||||
this.setIcon('network-cellular-signal-' + signalToIcon(dev.mobileDevice.signal_quality));
|
||||
hasMobileIcon = true;
|
||||
break;
|
||||
case NMConnectionCategory.VPN:
|
||||
this.setIcon('network-vpn');
|
||||
break;
|
||||
default:
|
||||
// fallback to a generic connected icon
|
||||
// (it could be a private connection of some other user)
|
||||
@ -2138,6 +2155,25 @@ const NMApplet = new Lang.Class({
|
||||
}
|
||||
}
|
||||
|
||||
// update VPN indicator
|
||||
if (this._vpnConnection) {
|
||||
let vpnIconName = 'network-vpn';
|
||||
if (this._vpnConnection.state == NetworkManager.ActiveConnectionState.ACTIVATING)
|
||||
vpnIconName = 'network-vpn-acquiring';
|
||||
|
||||
// only show a separate icon when we're using a wireless/3g connection
|
||||
if (mc._section == NMConnectionCategory.WIRELESS ||
|
||||
mc._section == NMConnectionCategory.WWAN) {
|
||||
this._secondaryIcon.icon_name = vpnIconName;
|
||||
this._secondaryIcon.visible = true;
|
||||
} else {
|
||||
this.setIcon(vpnIconName);
|
||||
this._secondaryIcon.visible = false;
|
||||
}
|
||||
} else {
|
||||
this._secondaryIcon.visible = false;
|
||||
}
|
||||
|
||||
// cleanup stale signal connections
|
||||
|
||||
if (!hasApIcon && this._activeAccessPointUpdateId) {
|
||||
|
@ -132,6 +132,9 @@ const Client = new Lang.Class({
|
||||
let channel = channels[i];
|
||||
let [targetHandle, targetHandleType] = channel.get_handle();
|
||||
|
||||
if (Shell.is_channel_invalidated(channel))
|
||||
continue;
|
||||
|
||||
/* Only observe contact text channels */
|
||||
if ((!(channel instanceof Tp.TextChannel)) ||
|
||||
targetHandleType != Tp.HandleType.CONTACT)
|
||||
@ -181,6 +184,9 @@ const Client = new Lang.Class({
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Shell.is_channel_invalidated(channel))
|
||||
continue;
|
||||
|
||||
// 'notify' will be true when coming from an actual HandleChannels
|
||||
// call, and not when from a successful Claim call. The point is
|
||||
// we don't want to notify for a channel we just claimed which
|
||||
@ -231,12 +237,19 @@ const Client = new Lang.Class({
|
||||
let channel = channels[0];
|
||||
let chanType = channel.get_channel_type();
|
||||
|
||||
if (Shell.is_channel_invalidated(channel)) {
|
||||
Shell.decline_dispatch_op(context, 'Channel is invalidated');
|
||||
return;
|
||||
}
|
||||
|
||||
if (chanType == Tp.IFACE_CHANNEL_TYPE_TEXT)
|
||||
this._approveTextChannel(account, conn, channel, dispatchOp, context);
|
||||
else if (chanType == Tp.IFACE_CHANNEL_TYPE_CALL)
|
||||
this._approveCall(account, conn, channel, dispatchOp, context);
|
||||
else if (chanType == Tp.IFACE_CHANNEL_TYPE_FILE_TRANSFER)
|
||||
this._approveFileTransfer(account, conn, channel, dispatchOp, context);
|
||||
else
|
||||
Shell.decline_dispatch_op(context, 'Unsupported channel type');
|
||||
},
|
||||
|
||||
_approveTextChannel: function(account, conn, channel, dispatchOp, context) {
|
||||
@ -802,7 +815,7 @@ const ChatNotification = new Lang.Class({
|
||||
let groups = this._contentArea.get_children();
|
||||
for (let i = 0; i < groups.length; i++) {
|
||||
let group = groups[i];
|
||||
if (group.get_children().length == 0)
|
||||
if (group.get_n_children() == 0)
|
||||
group.destroy();
|
||||
}
|
||||
},
|
||||
|
@ -133,7 +133,7 @@ const IMStatusChooserItem = new Lang.Class({
|
||||
item = new IMStatusItem(_("Busy"), 'user-busy');
|
||||
this._combo.addMenuItem(item, IMStatus.BUSY);
|
||||
|
||||
item = new IMStatusItem(_("Hidden"), 'user-invisible');
|
||||
item = new IMStatusItem(_("Invisible"), 'user-invisible');
|
||||
this._combo.addMenuItem(item, IMStatus.HIDDEN);
|
||||
|
||||
item = new IMStatusItem(_("Away"), 'user-away');
|
||||
|
@ -1121,25 +1121,6 @@ const Workspace = new Lang.Class({
|
||||
}
|
||||
},
|
||||
|
||||
_showAllOverlays: function() {
|
||||
let currentWorkspace = global.screen.get_active_workspace();
|
||||
for (let i = 0; i < this._windows.length; i++) {
|
||||
let clone = this._windows[i];
|
||||
let overlay = this._windowOverlays[i];
|
||||
this._showWindowOverlay(clone, overlay,
|
||||
this.metaWorkspace == null || this.metaWorkspace == currentWorkspace);
|
||||
}
|
||||
},
|
||||
|
||||
_hideAllOverlays: function() {
|
||||
for (let i = 0; i < this._windows.length; i++) {
|
||||
let clone = this._windows[i];
|
||||
let overlay = this._windowOverlays[i];
|
||||
if (overlay)
|
||||
overlay.hide();
|
||||
}
|
||||
},
|
||||
|
||||
_delayedWindowRepositioning: function() {
|
||||
if (this._windowIsZooming)
|
||||
return true;
|
||||
@ -1339,6 +1320,10 @@ const Workspace = new Lang.Class({
|
||||
// Position and scale the windows.
|
||||
for (let i = 0; i < this._windows.length; i++) {
|
||||
let clone = this._windows[i];
|
||||
let overlay = this._windowOverlays[i];
|
||||
|
||||
if (overlay)
|
||||
overlay.hide();
|
||||
|
||||
clone.zoomFromOverview();
|
||||
|
||||
@ -1363,8 +1348,6 @@ const Workspace = new Lang.Class({
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this._hideAllOverlays();
|
||||
},
|
||||
|
||||
destroy : function() {
|
||||
|
@ -1,6 +1,6 @@
|
||||
data/gnome-shell.desktop.in.in
|
||||
data/gnome-shell-extension-prefs.desktop.in.in
|
||||
data/org.gnome.shell.gschema.xml.in
|
||||
data/org.gnome.shell.gschema.xml.in.in
|
||||
js/extensionPrefs/main.js
|
||||
js/gdm/loginDialog.js
|
||||
js/gdm/powerMenu.js
|
||||
@ -13,6 +13,7 @@ js/ui/contactDisplay.js
|
||||
js/ui/dash.js
|
||||
js/ui/dateMenu.js
|
||||
js/ui/endSessionDialog.js
|
||||
js/ui/extensionDownloader.js
|
||||
js/ui/extensionSystem.js
|
||||
js/ui/keyboard.js
|
||||
js/ui/keyringPrompt.js
|
||||
|
4
po/lt.po
4
po/lt.po
@ -1705,11 +1705,11 @@ msgstr ""
|
||||
#: ../js/ui/wanda.js:128
|
||||
#, c-format
|
||||
msgid "%s the Oracle says"
|
||||
msgstr "Orakulė sako %s"
|
||||
msgstr "Orakulė %s sako"
|
||||
|
||||
#: ../js/ui/wanda.js:168
|
||||
msgid "Your favorite Easter Egg"
|
||||
msgstr "Jūsų mėgstamiausias Velykinis kiaušinis"
|
||||
msgstr "Jūsų mėgstamiausias velykinis kiaušinis"
|
||||
|
||||
#: ../js/ui/windowAttentionHandler.js:19
|
||||
#, c-format
|
||||
|
247
po/nb.po
247
po/nb.po
@ -8,8 +8,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell 3.5.x\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2012-05-30 14:16+0200\n"
|
||||
"PO-Revision-Date: 2012-05-30 14:19+0200\n"
|
||||
"POT-Creation-Date: 2012-06-11 22:04+0200\n"
|
||||
"PO-Revision-Date: 2012-06-11 22:04+0200\n"
|
||||
"Last-Translator: Kjartan Maraas <kmaraas@gnome.org>\n"
|
||||
"Language-Team: Norwegian bokmål <i18n-nb@lister.ping.uio.no>\n"
|
||||
"Language: \n"
|
||||
@ -35,11 +35,11 @@ msgstr "Brukervalg for GNOME Shell utvidelser"
|
||||
msgid "Configure GNOME Shell Extensions"
|
||||
msgstr "Konfigurer utvidelser for GNOME Shell"
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:1
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:1
|
||||
msgid "Enable internal tools useful for developers and testers from Alt-F2"
|
||||
msgstr "Aktiver interne verktøy for utviklere og testere fra Alt-F2"
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:2
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:2
|
||||
msgid ""
|
||||
"Allows access to internal debugging and monitoring tools using the Alt-F2 "
|
||||
"dialog."
|
||||
@ -47,11 +47,11 @@ msgstr ""
|
||||
"Tillat tilgang til interne feilsøkings- og overvåkingsverktøy ved å bruke "
|
||||
"Alt-F2-dialogen."
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:3
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:3
|
||||
msgid "Uuids of extensions to enable"
|
||||
msgstr "Uuider på utvidelser som skal slås på"
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:4
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:4
|
||||
msgid ""
|
||||
"GNOME Shell extensions have a uuid property; this key lists extensions which "
|
||||
"should be loaded. Any extension that wants to be loaded needs to be in this "
|
||||
@ -63,11 +63,11 @@ msgstr ""
|
||||
"i denne listen. Du kan også manipulere denne listen med DBus-metodene "
|
||||
"EnablExtension og DisableExtension på org.gnome.Shell."
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:5
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:5
|
||||
msgid "Whether to collect stats about applications usage"
|
||||
msgstr "Om det skal samles statistikk om bruk av programmer"
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:6
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:6
|
||||
msgid ""
|
||||
"The shell normally monitors active applications in order to present the most "
|
||||
"used ones (e.g. in launchers). While this data will be kept private, you may "
|
||||
@ -79,11 +79,11 @@ msgstr ""
|
||||
"holdt privat, men du kan deaktivere denne lagringen av personvernårsaker. "
|
||||
"Hvis du slår det av, vil det ikke fjerne allerede lagret informasjon."
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:7
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:7
|
||||
msgid "List of desktop file IDs for favorite applications"
|
||||
msgstr "Liste av skrivebordfil-ider for favorittprogrammer"
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:8
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:8
|
||||
msgid ""
|
||||
"The applications corresponding to these identifiers will be displayed in the "
|
||||
"favorites area."
|
||||
@ -91,83 +91,83 @@ msgstr ""
|
||||
"Programmene som passer til disse identifikatorene vil bli vist i "
|
||||
"favorittområdet."
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:9
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:9
|
||||
msgid "disabled OpenSearch providers"
|
||||
msgstr "OpenSearch tilbydere slått av"
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:10
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:10
|
||||
msgid "History for command (Alt-F2) dialog"
|
||||
msgstr "Historikk for kommandodialog (Alt-F2)"
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:11
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:11
|
||||
msgid "History for the looking glass dialog"
|
||||
msgstr "Historikk for forstørrelsesglass-dialogen"
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:12
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:12
|
||||
msgid ""
|
||||
"Internally used to store the last IM presence explicitly set by the user. "
|
||||
"The value here is from the TpConnectionPresenceType enumeration."
|
||||
msgstr ""
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:13
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:13
|
||||
msgid ""
|
||||
"Internally used to store the last session presence status for the user. The "
|
||||
"value here is from the GsmPresenceStatus enumeration."
|
||||
msgstr ""
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:14
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:14
|
||||
msgid "Show the week date in the calendar"
|
||||
msgstr "Vis dato for uken i kalender"
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:15
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:15
|
||||
msgid "If true, display the ISO week date in the calendar."
|
||||
msgstr "Viser ISO-ukedato i kalenderen hvis «true»."
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:16
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:16
|
||||
msgid "Keybinding to open the application menu"
|
||||
msgstr "Tastaturbinding som åpner programmenyen"
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:17
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:17
|
||||
msgid "Keybinding to open the application menu."
|
||||
msgstr "Tastaturbinding som åpner programmenyen."
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:18
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:18
|
||||
msgid "Keybinding to toggle the screen recorder"
|
||||
msgstr "Tastaturbinding som slår av/på skjermopptak"
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:19
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:19
|
||||
msgid "Keybinding to start/stop the builtin screen recorder."
|
||||
msgstr "Tastaturbinding som starter/stopper innebygget opptak av skjerm."
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:20
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:20
|
||||
msgid "Which keyboard to use"
|
||||
msgstr "Tastatur som skal brukes"
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:21
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:21
|
||||
msgid "The type of keyboard to use."
|
||||
msgstr "Type tastatur som skal brukes."
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:22
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:22
|
||||
msgid "Show time with seconds"
|
||||
msgstr "Vis tid med sekunder"
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:23
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:23
|
||||
msgid "If true, display seconds in time."
|
||||
msgstr "Viser sekunder i klokken hvis «true»."
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:24
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:24
|
||||
msgid "Show date in clock"
|
||||
msgstr "Vis dato i klokken"
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:25
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:25
|
||||
msgid "If true, display date in the clock, in addition to time."
|
||||
msgstr "Viser dato i tillegg til tid i klokken hvis «true»."
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:26
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:26
|
||||
msgid "Framerate used for recording screencasts."
|
||||
msgstr "Bildefrekvens i bruk ved lagring av skjermvideoer."
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:27
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:27
|
||||
msgid ""
|
||||
"The framerate of the resulting screencast recordered by GNOME Shell's "
|
||||
"screencast recorder in frames-per-second."
|
||||
@ -175,11 +175,11 @@ msgstr ""
|
||||
"Bildefrekvensen i den ferdige skjermvideoen tatt opp med GNOME Shells "
|
||||
"skjermvideoopptaker i bilder per sekund."
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:28
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:28
|
||||
msgid "The gstreamer pipeline used to encode the screencast"
|
||||
msgstr "Gstreamer-kommandokø brukt til å kode skjermvideoen"
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:30
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:30
|
||||
#, fuzzy, no-c-format
|
||||
msgid ""
|
||||
"Sets the GStreamer pipeline used to encode recordings. It follows the syntax "
|
||||
@ -196,11 +196,11 @@ msgstr ""
|
||||
"Setter GStreamer-rør som brukes til å kode opptak. Den følger syntaksen som "
|
||||
"brukes for gst-launch. Røret må ha en..."
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:31
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:31
|
||||
msgid "File extension used for storing the screencast"
|
||||
msgstr "Filendelse i bruk ved lagring av skjermvideo"
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:32
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:32
|
||||
msgid ""
|
||||
"The filename for recorded screencasts will be a unique filename based on the "
|
||||
"current date, and use this extension. It should be changed when recording to "
|
||||
@ -245,9 +245,9 @@ msgstr "(eller dra finger)"
|
||||
msgid "Not listed?"
|
||||
msgstr "Ikke listet?"
|
||||
|
||||
#: ../js/gdm/loginDialog.js:1023 ../js/ui/endSessionDialog.js:401
|
||||
#: ../js/ui/extensionSystem.js:375 ../js/ui/networkAgent.js:153
|
||||
#: ../js/ui/polkitAuthenticationAgent.js:175 ../js/ui/status/bluetooth.js:431
|
||||
#: ../js/gdm/loginDialog.js:1023 ../js/ui/endSessionDialog.js:410
|
||||
#: ../js/ui/extensionSystem.js:376 ../js/ui/networkAgent.js:153
|
||||
#: ../js/ui/polkitAuthenticationAgent.js:176 ../js/ui/status/bluetooth.js:431
|
||||
msgid "Cancel"
|
||||
msgstr "Avbryt"
|
||||
|
||||
@ -260,8 +260,8 @@ msgstr "Logg inn"
|
||||
msgid "Login Window"
|
||||
msgstr "Innloggingsvindu"
|
||||
|
||||
#: ../js/gdm/powerMenu.js:130 ../js/ui/userMenu.js:595
|
||||
#: ../js/ui/userMenu.js:599 ../js/ui/userMenu.js:647
|
||||
#: ../js/gdm/powerMenu.js:130 ../js/ui/userMenu.js:604
|
||||
#: ../js/ui/userMenu.js:608 ../js/ui/userMenu.js:696
|
||||
msgid "Suspend"
|
||||
msgstr "Hvilemodus"
|
||||
|
||||
@ -269,8 +269,8 @@ msgstr "Hvilemodus"
|
||||
msgid "Restart"
|
||||
msgstr "Start på nytt"
|
||||
|
||||
#: ../js/gdm/powerMenu.js:140 ../js/ui/userMenu.js:597
|
||||
#: ../js/ui/userMenu.js:599 ../js/ui/userMenu.js:646
|
||||
#: ../js/gdm/powerMenu.js:140 ../js/ui/userMenu.js:606
|
||||
#: ../js/ui/userMenu.js:608 ../js/ui/userMenu.js:695
|
||||
msgid "Power Off"
|
||||
msgstr "Slå av"
|
||||
|
||||
@ -290,27 +290,27 @@ msgid "Execution of '%s' failed:"
|
||||
msgstr "Kjøring av «%s» feilet:"
|
||||
|
||||
#. Translators: Filter to display all applications
|
||||
#: ../js/ui/appDisplay.js:255
|
||||
#: ../js/ui/appDisplay.js:251
|
||||
msgid "All"
|
||||
msgstr "Alle"
|
||||
|
||||
#: ../js/ui/appDisplay.js:314
|
||||
#: ../js/ui/appDisplay.js:309
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "PROGRAMMER"
|
||||
|
||||
#: ../js/ui/appDisplay.js:374
|
||||
#: ../js/ui/appDisplay.js:369
|
||||
msgid "SETTINGS"
|
||||
msgstr "INNSTILLINGER"
|
||||
|
||||
#: ../js/ui/appDisplay.js:679
|
||||
#: ../js/ui/appDisplay.js:674
|
||||
msgid "New Window"
|
||||
msgstr "Nytt vindu"
|
||||
|
||||
#: ../js/ui/appDisplay.js:682
|
||||
#: ../js/ui/appDisplay.js:677
|
||||
msgid "Remove from Favorites"
|
||||
msgstr "Fjern fra favoritter"
|
||||
|
||||
#: ../js/ui/appDisplay.js:683
|
||||
#: ../js/ui/appDisplay.js:678
|
||||
msgid "Add to Favorites"
|
||||
msgstr "Legg til i favoritter"
|
||||
|
||||
@ -483,8 +483,8 @@ msgstr "Denne uken"
|
||||
msgid "Next week"
|
||||
msgstr "Neste uke"
|
||||
|
||||
#: ../js/ui/contactDisplay.js:66 ../js/ui/notificationDaemon.js:486
|
||||
#: ../js/ui/status/power.js:215 ../src/shell-app.c:374
|
||||
#: ../js/ui/contactDisplay.js:66
|
||||
msgctxt "contact"
|
||||
msgid "Unknown"
|
||||
msgstr "Ukjent"
|
||||
|
||||
@ -567,103 +567,103 @@ msgstr "%a %l.%M %p"
|
||||
msgid "%A %B %e, %Y"
|
||||
msgstr "%a %e %B, %Y"
|
||||
|
||||
#: ../js/ui/endSessionDialog.js:61
|
||||
#: ../js/ui/endSessionDialog.js:60
|
||||
#, c-format
|
||||
msgctxt "title"
|
||||
msgid "Log Out %s"
|
||||
msgstr "Logg ut %s"
|
||||
|
||||
#: ../js/ui/endSessionDialog.js:62
|
||||
#: ../js/ui/endSessionDialog.js:61
|
||||
msgctxt "title"
|
||||
msgid "Log Out"
|
||||
msgstr "Logg ut"
|
||||
|
||||
#: ../js/ui/endSessionDialog.js:63
|
||||
#: ../js/ui/endSessionDialog.js:62
|
||||
msgid "Click Log Out to quit these applications and log out of the system."
|
||||
msgstr ""
|
||||
"Klikk Logg ut for å avslutte disse programmene og logge ut av systemet."
|
||||
|
||||
#: ../js/ui/endSessionDialog.js:65
|
||||
#: ../js/ui/endSessionDialog.js:64
|
||||
#, c-format
|
||||
msgid "%s will be logged out automatically in %d second."
|
||||
msgid_plural "%s will be logged out automatically in %d seconds."
|
||||
msgstr[0] "%s vil bli logget ut automatisk om %d sekund."
|
||||
msgstr[1] "%s vil bli logget ut automatisk om %d sekunder."
|
||||
|
||||
#: ../js/ui/endSessionDialog.js:70
|
||||
#: ../js/ui/endSessionDialog.js:69
|
||||
#, c-format
|
||||
msgid "You will be logged out automatically in %d second."
|
||||
msgid_plural "You will be logged out automatically in %d seconds."
|
||||
msgstr[0] "Du vil bli logget ut automatisk om %d sekund."
|
||||
msgstr[1] "Du vil bli logget ut automatisk om %d sekunder."
|
||||
|
||||
#: ../js/ui/endSessionDialog.js:74
|
||||
#: ../js/ui/endSessionDialog.js:73
|
||||
msgid "Logging out of the system."
|
||||
msgstr "Logger ut av systemet"
|
||||
|
||||
#: ../js/ui/endSessionDialog.js:76
|
||||
#: ../js/ui/endSessionDialog.js:75
|
||||
msgctxt "button"
|
||||
msgid "Log Out"
|
||||
msgstr "Logg ut"
|
||||
|
||||
#: ../js/ui/endSessionDialog.js:81
|
||||
#: ../js/ui/endSessionDialog.js:80
|
||||
msgctxt "title"
|
||||
msgid "Power Off"
|
||||
msgstr "Slå av"
|
||||
|
||||
#: ../js/ui/endSessionDialog.js:82
|
||||
#: ../js/ui/endSessionDialog.js:81
|
||||
msgid "Click Power Off to quit these applications and power off the system."
|
||||
msgstr ""
|
||||
"Klikk «Slå av» for å avslutte disse programmene og logge ut av systemet."
|
||||
|
||||
#: ../js/ui/endSessionDialog.js:84
|
||||
#: ../js/ui/endSessionDialog.js:83
|
||||
#, c-format
|
||||
msgid "The system will power off automatically in %d second."
|
||||
msgid_plural "The system will power off automatically in %d seconds."
|
||||
msgstr[0] "Systemet vil slås av automatisk om %d sekund."
|
||||
msgstr[1] "Systemet vil slås av automatisk om %d sekunder."
|
||||
|
||||
#: ../js/ui/endSessionDialog.js:88
|
||||
#: ../js/ui/endSessionDialog.js:87
|
||||
msgid "Powering off the system."
|
||||
msgstr "Slår av systemet."
|
||||
|
||||
#: ../js/ui/endSessionDialog.js:90 ../js/ui/endSessionDialog.js:107
|
||||
#: ../js/ui/endSessionDialog.js:89 ../js/ui/endSessionDialog.js:106
|
||||
msgctxt "button"
|
||||
msgid "Restart"
|
||||
msgstr "Start på nytt"
|
||||
|
||||
#: ../js/ui/endSessionDialog.js:92
|
||||
#: ../js/ui/endSessionDialog.js:91
|
||||
msgctxt "button"
|
||||
msgid "Power Off"
|
||||
msgstr "Slå av"
|
||||
|
||||
#: ../js/ui/endSessionDialog.js:98
|
||||
#: ../js/ui/endSessionDialog.js:97
|
||||
msgctxt "title"
|
||||
msgid "Restart"
|
||||
msgstr "Start på nytt"
|
||||
|
||||
#: ../js/ui/endSessionDialog.js:99
|
||||
#: ../js/ui/endSessionDialog.js:98
|
||||
msgid "Click Restart to quit these applications and restart the system."
|
||||
msgstr ""
|
||||
"Klikk Start på nytt for å avslutte disse programmene og starte systemet på "
|
||||
"nytt."
|
||||
|
||||
#: ../js/ui/endSessionDialog.js:101
|
||||
#: ../js/ui/endSessionDialog.js:100
|
||||
#, c-format
|
||||
msgid "The system will restart automatically in %d second."
|
||||
msgid_plural "The system will restart automatically in %d seconds."
|
||||
msgstr[0] "Systemet vil starte på nytt automatisk om %d sekund."
|
||||
msgstr[1] "Systemet vil starte på nytt automatisk om %d sekunder."
|
||||
|
||||
#: ../js/ui/endSessionDialog.js:105
|
||||
#: ../js/ui/endSessionDialog.js:104
|
||||
msgid "Restarting the system."
|
||||
msgstr "Starter systemet på nytt."
|
||||
|
||||
#: ../js/ui/extensionSystem.js:379
|
||||
#: ../js/ui/extensionSystem.js:380
|
||||
msgid "Install"
|
||||
msgstr "Installer"
|
||||
|
||||
#: ../js/ui/extensionSystem.js:383
|
||||
#: ../js/ui/extensionSystem.js:384
|
||||
#, c-format
|
||||
msgid "Download and install '%s' from extensions.gnome.org?"
|
||||
msgstr "Last ned og installer «%s» fra extensions.gnome.org?"
|
||||
@ -672,12 +672,12 @@ msgstr "Last ned og installer «%s» fra extensions.gnome.org?"
|
||||
msgid "tray"
|
||||
msgstr "varslingsområde"
|
||||
|
||||
#: ../js/ui/keyboard.js:545 ../js/ui/status/keyboard.js:44
|
||||
#: ../js/ui/keyboard.js:545 ../js/ui/status/keyboard.js:42
|
||||
#: ../js/ui/status/power.js:203
|
||||
msgid "Keyboard"
|
||||
msgstr "Tastatur"
|
||||
|
||||
#: ../js/ui/keyringPrompt.js:85 ../js/ui/polkitAuthenticationAgent.js:272
|
||||
#: ../js/ui/keyringPrompt.js:85 ../js/ui/polkitAuthenticationAgent.js:273
|
||||
msgid "Password:"
|
||||
msgstr "Passord:"
|
||||
|
||||
@ -734,7 +734,7 @@ msgid "Web Page"
|
||||
msgstr "Nettside"
|
||||
|
||||
#. Translators: this is a filename used for screencast recording
|
||||
#: ../js/ui/main.js:121
|
||||
#: ../js/ui/main.js:126
|
||||
#, no-c-format
|
||||
msgid "Screencast from %d %t"
|
||||
msgstr "Skjermvideo fra %d %t"
|
||||
@ -751,7 +751,7 @@ msgstr "Fjern demping"
|
||||
msgid "Mute"
|
||||
msgstr "Demp"
|
||||
|
||||
#: ../js/ui/messageTray.js:2522
|
||||
#: ../js/ui/messageTray.js:2528
|
||||
msgid "System Information"
|
||||
msgstr "Systeminformasjon"
|
||||
|
||||
@ -836,25 +836,30 @@ msgstr "Nettverkspassord for mobilt bredbånd"
|
||||
msgid "A password is required to connect to '%s'."
|
||||
msgstr "Et passord kreves for å koble til «%s»."
|
||||
|
||||
#: ../js/ui/overview.js:90
|
||||
#: ../js/ui/notificationDaemon.js:486 ../src/shell-app.c:374
|
||||
msgctxt "program"
|
||||
msgid "Unknown"
|
||||
msgstr "Ukjent"
|
||||
|
||||
#: ../js/ui/overview.js:89
|
||||
msgid "Undo"
|
||||
msgstr "Angre"
|
||||
|
||||
#: ../js/ui/overview.js:130
|
||||
#: ../js/ui/overview.js:129
|
||||
msgid "Overview"
|
||||
msgstr "Oversikt"
|
||||
|
||||
#: ../js/ui/overview.js:200
|
||||
#: ../js/ui/overview.js:199
|
||||
msgid "Windows"
|
||||
msgstr "Vinduer"
|
||||
|
||||
#: ../js/ui/overview.js:203
|
||||
#: ../js/ui/overview.js:202
|
||||
msgid "Applications"
|
||||
msgstr "Programmer"
|
||||
|
||||
#. Translators: this is the name of the dock/favorites area on
|
||||
#. the left of the overview
|
||||
#: ../js/ui/overview.js:229
|
||||
#: ../js/ui/overview.js:228
|
||||
msgid "Dash"
|
||||
msgstr "Favoritter"
|
||||
|
||||
@ -897,7 +902,7 @@ msgstr "Autentisering kreves"
|
||||
msgid "Administrator"
|
||||
msgstr "Administrator"
|
||||
|
||||
#: ../js/ui/polkitAuthenticationAgent.js:179
|
||||
#: ../js/ui/polkitAuthenticationAgent.js:180
|
||||
msgid "Authenticate"
|
||||
msgstr "Autentiser"
|
||||
|
||||
@ -905,7 +910,7 @@ msgstr "Autentiser"
|
||||
#. * requested authentication was not gained; this can happen
|
||||
#. * because of an authentication error (like invalid password),
|
||||
#. * for instance.
|
||||
#: ../js/ui/polkitAuthenticationAgent.js:260
|
||||
#: ../js/ui/polkitAuthenticationAgent.js:261
|
||||
msgid "Sorry, that didn't work. Please try again."
|
||||
msgstr "Beklager, det virket ikke. Vennligst prøv igjen."
|
||||
|
||||
@ -922,11 +927,11 @@ msgstr "toggle-switch-intl"
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Oppgi en kommando:"
|
||||
|
||||
#: ../js/ui/searchDisplay.js:321
|
||||
#: ../js/ui/searchDisplay.js:323
|
||||
msgid "Searching..."
|
||||
msgstr "Søker …"
|
||||
|
||||
#: ../js/ui/searchDisplay.js:374
|
||||
#: ../js/ui/searchDisplay.js:376
|
||||
msgid "No matching results."
|
||||
msgstr "Ingen treff."
|
||||
|
||||
@ -1000,7 +1005,7 @@ msgstr "Stor tekst"
|
||||
#: ../js/ui/status/bluetooth.js:31 ../js/ui/status/bluetooth.js:35
|
||||
#: ../js/ui/status/bluetooth.js:255 ../js/ui/status/bluetooth.js:308
|
||||
#: ../js/ui/status/bluetooth.js:339 ../js/ui/status/bluetooth.js:375
|
||||
#: ../js/ui/status/bluetooth.js:404 ../js/ui/status/network.js:890
|
||||
#: ../js/ui/status/bluetooth.js:404 ../js/ui/status/network.js:889
|
||||
msgid "Bluetooth"
|
||||
msgstr "Bluetooth"
|
||||
|
||||
@ -1029,11 +1034,12 @@ msgstr "maskinvare slått av"
|
||||
msgid "Connection"
|
||||
msgstr "Tilkobling"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:211 ../js/ui/status/network.js:491
|
||||
#: ../js/ui/status/bluetooth.js:211 ../js/ui/status/network.js:490
|
||||
msgid "disconnecting..."
|
||||
msgstr "kobler fra …"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:224 ../js/ui/status/network.js:497
|
||||
#: ../js/ui/status/bluetooth.js:224 ../js/ui/status/network.js:496
|
||||
#: ../js/ui/status/network.js:956
|
||||
msgid "connecting..."
|
||||
msgstr "kobler til …"
|
||||
|
||||
@ -1124,11 +1130,11 @@ msgstr "Vennligst oppgi PIN som oppgitt på enheten."
|
||||
msgid "OK"
|
||||
msgstr "OK"
|
||||
|
||||
#: ../js/ui/status/keyboard.js:72
|
||||
#: ../js/ui/status/keyboard.js:69
|
||||
msgid "Show Keyboard Layout"
|
||||
msgstr "Vis tastaturutforming"
|
||||
|
||||
#: ../js/ui/status/keyboard.js:77
|
||||
#: ../js/ui/status/keyboard.js:71
|
||||
msgid "Region and Language Settings"
|
||||
msgstr "Innstillinger for region og språk"
|
||||
|
||||
@ -1143,113 +1149,113 @@ msgstr "slått av"
|
||||
|
||||
#. 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:489
|
||||
#: ../js/ui/status/network.js:488
|
||||
msgid "unmanaged"
|
||||
msgstr "ikke håndtert"
|
||||
|
||||
#. Translators: this is for network connections that require some kind of key or password
|
||||
#: ../js/ui/status/network.js:500
|
||||
#: ../js/ui/status/network.js:499 ../js/ui/status/network.js:959
|
||||
msgid "authentication required"
|
||||
msgstr "autentisering kreves"
|
||||
|
||||
#. Translators: this is for devices that require some kind of firmware or kernel
|
||||
#. module, which is missing
|
||||
#: ../js/ui/status/network.js:510
|
||||
#: ../js/ui/status/network.js:509
|
||||
msgid "firmware missing"
|
||||
msgstr "fastvare mangler"
|
||||
|
||||
#. Translators: this is for wired network devices that are physically disconnected
|
||||
#: ../js/ui/status/network.js:517
|
||||
#: ../js/ui/status/network.js:516
|
||||
msgid "cable unplugged"
|
||||
msgstr "kabel koblet fra"
|
||||
|
||||
#. 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:522
|
||||
#: ../js/ui/status/network.js:521
|
||||
msgid "unavailable"
|
||||
msgstr "ikke tilgjengelig"
|
||||
|
||||
#: ../js/ui/status/network.js:524
|
||||
#: ../js/ui/status/network.js:523 ../js/ui/status/network.js:961
|
||||
msgid "connection failed"
|
||||
msgstr "tilkobling feilet"
|
||||
|
||||
#: ../js/ui/status/network.js:585 ../js/ui/status/network.js:1497
|
||||
#: ../js/ui/status/network.js:584 ../js/ui/status/network.js:1529
|
||||
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:621 ../js/ui/status/network.js:1432
|
||||
#: ../js/ui/status/network.js:620 ../js/ui/status/network.js:1459
|
||||
msgid "Connected (private)"
|
||||
msgstr "Tilkoblet (privat)"
|
||||
|
||||
#: ../js/ui/status/network.js:696
|
||||
#: ../js/ui/status/network.js:695
|
||||
msgid "Auto Ethernet"
|
||||
msgstr "Automatisk Ethernet"
|
||||
|
||||
#: ../js/ui/status/network.js:754
|
||||
#: ../js/ui/status/network.js:753
|
||||
msgid "Auto broadband"
|
||||
msgstr "Automatisk bredbånd"
|
||||
|
||||
#: ../js/ui/status/network.js:757
|
||||
#: ../js/ui/status/network.js:756
|
||||
msgid "Auto dial-up"
|
||||
msgstr "Automatisk oppringt"
|
||||
|
||||
#. TRANSLATORS: this the automatic wireless connection name (including the network name)
|
||||
#: ../js/ui/status/network.js:876 ../js/ui/status/network.js:1444
|
||||
#: ../js/ui/status/network.js:875 ../js/ui/status/network.js:1476
|
||||
#, c-format
|
||||
msgid "Auto %s"
|
||||
msgstr "Automatisk %s"
|
||||
|
||||
#: ../js/ui/status/network.js:878
|
||||
#: ../js/ui/status/network.js:877
|
||||
msgid "Auto bluetooth"
|
||||
msgstr "Automatisk Bluetooth"
|
||||
|
||||
#: ../js/ui/status/network.js:1446
|
||||
#: ../js/ui/status/network.js:1478
|
||||
msgid "Auto wireless"
|
||||
msgstr "Automatisk trådløst"
|
||||
|
||||
#: ../js/ui/status/network.js:1533
|
||||
#: ../js/ui/status/network.js:1565
|
||||
msgid "Network"
|
||||
msgstr "Nettverk"
|
||||
|
||||
#: ../js/ui/status/network.js:1540
|
||||
#: ../js/ui/status/network.js:1572
|
||||
msgid "Enable networking"
|
||||
msgstr "Slå på nettverk"
|
||||
|
||||
#: ../js/ui/status/network.js:1552
|
||||
#: ../js/ui/status/network.js:1593
|
||||
msgid "Wired"
|
||||
msgstr "Kablet"
|
||||
|
||||
#: ../js/ui/status/network.js:1563
|
||||
#: ../js/ui/status/network.js:1604
|
||||
msgid "Wireless"
|
||||
msgstr "Trådløst"
|
||||
|
||||
#: ../js/ui/status/network.js:1573
|
||||
#: ../js/ui/status/network.js:1614
|
||||
msgid "Mobile broadband"
|
||||
msgstr "Mobilt bredbånd"
|
||||
|
||||
#: ../js/ui/status/network.js:1583
|
||||
#: ../js/ui/status/network.js:1624
|
||||
msgid "VPN Connections"
|
||||
msgstr "VPN-tilkoblinger"
|
||||
|
||||
#: ../js/ui/status/network.js:1594
|
||||
#: ../js/ui/status/network.js:1631
|
||||
msgid "Network Settings"
|
||||
msgstr "Innstillinger for nettverk"
|
||||
|
||||
#: ../js/ui/status/network.js:1647
|
||||
#: ../js/ui/status/network.js:1675
|
||||
msgid "Network Manager"
|
||||
msgstr "Nettverkshåndtering"
|
||||
|
||||
#: ../js/ui/status/network.js:1734
|
||||
#: ../js/ui/status/network.js:1768
|
||||
msgid "Connection failed"
|
||||
msgstr "Tilkobling feilet"
|
||||
|
||||
#: ../js/ui/status/network.js:1735
|
||||
#: ../js/ui/status/network.js:1769
|
||||
msgid "Activation of network connection failed"
|
||||
msgstr "Aktivering av nettverkstilkobling feilet"
|
||||
|
||||
#: ../js/ui/status/network.js:1988
|
||||
#: ../js/ui/status/network.js:2029
|
||||
msgid "Networking is disabled"
|
||||
msgstr "Nettverk er slått av"
|
||||
|
||||
@ -1345,6 +1351,11 @@ msgstr "Nettbrett"
|
||||
msgid "Computer"
|
||||
msgstr "Datamaskin"
|
||||
|
||||
#: ../js/ui/status/power.js:215
|
||||
msgctxt "device"
|
||||
msgid "Unknown"
|
||||
msgstr "Ukjent"
|
||||
|
||||
#. Translators: This is the label for audio volume
|
||||
#: ../js/ui/status/volume.js:25 ../js/ui/status/volume.js:39
|
||||
msgid "Volume"
|
||||
@ -1620,35 +1631,35 @@ msgstr "Ledig"
|
||||
msgid "Unavailable"
|
||||
msgstr "Ikke tilgjengelig"
|
||||
|
||||
#: ../js/ui/userMenu.js:556 ../js/ui/userMenu.js:656
|
||||
#: ../js/ui/userMenu.js:565 ../js/ui/userMenu.js:705
|
||||
msgid "Switch User"
|
||||
msgstr "Bytt bruker"
|
||||
|
||||
#: ../js/ui/userMenu.js:557
|
||||
#: ../js/ui/userMenu.js:566
|
||||
msgid "Switch Session"
|
||||
msgstr "Bytt økt"
|
||||
|
||||
#: ../js/ui/userMenu.js:632
|
||||
#: ../js/ui/userMenu.js:681
|
||||
msgid "Notifications"
|
||||
msgstr "Varslinger"
|
||||
|
||||
#: ../js/ui/userMenu.js:641
|
||||
#: ../js/ui/userMenu.js:690
|
||||
msgid "System Settings"
|
||||
msgstr "Systeminnstillinger"
|
||||
|
||||
#: ../js/ui/userMenu.js:661
|
||||
#: ../js/ui/userMenu.js:710
|
||||
msgid "Log Out"
|
||||
msgstr "Logg ut"
|
||||
|
||||
#: ../js/ui/userMenu.js:669
|
||||
#: ../js/ui/userMenu.js:718
|
||||
msgid "Lock"
|
||||
msgstr "Lås"
|
||||
|
||||
#: ../js/ui/userMenu.js:687
|
||||
#: ../js/ui/userMenu.js:736
|
||||
msgid "Your chat status will be set to busy"
|
||||
msgstr "Din pratestatus vil bli satt til opptatt"
|
||||
|
||||
#: ../js/ui/userMenu.js:688
|
||||
#: ../js/ui/userMenu.js:737
|
||||
msgid ""
|
||||
"Notifications are now disabled, including chat messages. Your online status "
|
||||
"has been adjusted to let others know that you might not see their messages."
|
||||
|
@ -109,7 +109,6 @@ shell_public_headers_h = \
|
||||
shell-app.h \
|
||||
shell-app-system.h \
|
||||
shell-app-usage.h \
|
||||
shell-contact-system.h \
|
||||
shell-embedded-window.h \
|
||||
shell-generic-container.h \
|
||||
shell-gtk-embed.h \
|
||||
@ -132,6 +131,10 @@ shell_public_headers_h = \
|
||||
shell-wm.h \
|
||||
shell-xfixes-cursor.h
|
||||
|
||||
if BUILD_WITH_FOLKS
|
||||
shell_public_headers_h += shell-contact-system.h
|
||||
endif
|
||||
|
||||
shell_private_sources = \
|
||||
gactionmuxer.h \
|
||||
gactionmuxer.c \
|
||||
@ -153,11 +156,8 @@ libgnome_shell_la_SOURCES = \
|
||||
shell-wm-private.h \
|
||||
gnome-shell-plugin.c \
|
||||
shell-app.c \
|
||||
shell-a11y.h \
|
||||
shell-a11y.c \
|
||||
shell-app-system.c \
|
||||
shell-app-usage.c \
|
||||
shell-contact-system.c \
|
||||
shell-embedded-window.c \
|
||||
shell-generic-container.c \
|
||||
shell-gtk-embed.c \
|
||||
@ -187,6 +187,9 @@ libgnome_shell_la_SOURCES = \
|
||||
shell-xfixes-cursor.c \
|
||||
$(NULL)
|
||||
|
||||
if BUILD_WITH_FOLKS
|
||||
libgnome_shell_la_SOURCES += shell-contact-system.c
|
||||
endif
|
||||
|
||||
libgnome_shell_la_gir_sources = \
|
||||
$(filter-out %-private.h $(shell_private_sources), $(shell_public_headers_h) $(libgnome_shell_la_SOURCES))
|
||||
@ -303,7 +306,10 @@ 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 Soup-2.4 GMenu-3.0 NetworkManager-1.0 NMClient-1.0 Folks-0.6
|
||||
Shell_0_1_gir_INCLUDES = Clutter-1.0 ClutterX11-1.0 Meta-3.0 TelepathyGLib-0.12 TelepathyLogger-0.2 Soup-2.4 GMenu-3.0 NetworkManager-1.0 NMClient-1.0
|
||||
if BUILD_WITH_FOLKS
|
||||
Shell_0_1_gir_INCLUDES += Folks-0.6
|
||||
endif
|
||||
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)
|
||||
|
@ -29,11 +29,9 @@
|
||||
|
||||
#include <libintl.h>
|
||||
#include <string.h>
|
||||
#include <gconf/gconf-client.h>
|
||||
#define HANDLE_LIBICAL_MEMORY
|
||||
#include <libecal/e-cal-client.h>
|
||||
#include <libedataserver/e-source-list.h>
|
||||
#include <libedataserverui/e-client-utils.h>
|
||||
#include <libecal/libecal.h>
|
||||
#include <libedataserverui/libedataserverui.h>
|
||||
|
||||
#undef CALENDAR_ENABLE_DEBUG
|
||||
#include "calendar-debug.h"
|
||||
@ -48,30 +46,23 @@
|
||||
|
||||
#define CALENDAR_SOURCES_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CALENDAR_TYPE_SOURCES, CalendarSourcesPrivate))
|
||||
|
||||
#define CALENDAR_SOURCES_EVO_DIR "/apps/evolution"
|
||||
#define CALENDAR_SOURCES_APPOINTMENT_SOURCES_KEY CALENDAR_SOURCES_EVO_DIR "/calendar/sources"
|
||||
#define CALENDAR_SOURCES_TASK_SOURCES_KEY CALENDAR_SOURCES_EVO_DIR "/tasks/sources"
|
||||
|
||||
/* org.gnome.shell.evolution.calendar has the same data behind it
|
||||
* as org.gnome.evolution.calendar, but is a small schema we install
|
||||
* ourselves */
|
||||
#define CALENDAR_SELECTED_SOURCES_SCHEMA "org.gnome.shell.evolution.calendar"
|
||||
#define CALENDAR_SOURCES_SELECTED_APPOINTMENT_SOURCES_KEY "selected-calendars"
|
||||
#define CALENDAR_SOURCES_SELECTED_TASK_SOURCES_KEY "selected-tasks"
|
||||
|
||||
typedef struct _ClientData ClientData;
|
||||
typedef struct _CalendarSourceData CalendarSourceData;
|
||||
|
||||
struct _ClientData
|
||||
{
|
||||
ECalClient *client;
|
||||
gulong backend_died_id;
|
||||
};
|
||||
|
||||
struct _CalendarSourceData
|
||||
{
|
||||
ECalClientSourceType source_type;
|
||||
CalendarSources *sources;
|
||||
guint changed_signal;
|
||||
|
||||
GSList *clients;
|
||||
char **selected_sources;
|
||||
ESourceList *esource_list;
|
||||
|
||||
guint selected_sources_handler_id;
|
||||
/* ESource -> EClient */
|
||||
GHashTable *clients;
|
||||
|
||||
guint timeout_id;
|
||||
|
||||
@ -80,11 +71,13 @@ struct _CalendarSourceData
|
||||
|
||||
struct _CalendarSourcesPrivate
|
||||
{
|
||||
ESourceRegistry *registry;
|
||||
gulong source_added_id;
|
||||
gulong source_changed_id;
|
||||
gulong source_removed_id;
|
||||
|
||||
CalendarSourceData appointment_sources;
|
||||
CalendarSourceData task_sources;
|
||||
|
||||
GConfClient *gconf_client;
|
||||
GSettings *settings;
|
||||
};
|
||||
|
||||
static void calendar_sources_class_init (CalendarSourcesClass *klass);
|
||||
@ -92,8 +85,12 @@ static void calendar_sources_init (CalendarSources *sources);
|
||||
static void calendar_sources_finalize (GObject *object);
|
||||
|
||||
static void backend_died_cb (EClient *client, CalendarSourceData *source_data);
|
||||
static void calendar_sources_esource_list_changed (ESourceList *source_list,
|
||||
CalendarSourceData *source_data);
|
||||
static void calendar_sources_registry_source_changed_cb (ESourceRegistry *registry,
|
||||
ESource *source,
|
||||
CalendarSources *sources);
|
||||
static void calendar_sources_registry_source_removed_cb (ESourceRegistry *registry,
|
||||
ESource *source,
|
||||
CalendarSources *sources);
|
||||
|
||||
enum
|
||||
{
|
||||
@ -106,6 +103,14 @@ static guint signals [LAST_SIGNAL] = { 0, };
|
||||
static GObjectClass *parent_class = NULL;
|
||||
static CalendarSources *calendar_sources_singleton = NULL;
|
||||
|
||||
static void
|
||||
client_data_free (ClientData *data)
|
||||
{
|
||||
g_signal_handler_disconnect (data->client, data->backend_died_id);
|
||||
g_object_unref (data->client);
|
||||
g_slice_free (ClientData, data);
|
||||
}
|
||||
|
||||
GType
|
||||
calendar_sources_get_type (void)
|
||||
{
|
||||
@ -173,20 +178,49 @@ calendar_sources_class_init (CalendarSourcesClass *klass)
|
||||
static void
|
||||
calendar_sources_init (CalendarSources *sources)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
sources->priv = CALENDAR_SOURCES_GET_PRIVATE (sources);
|
||||
|
||||
/* XXX Not sure what to do if this fails.
|
||||
* Should this class implement GInitable or pass the
|
||||
* registry in as a G_PARAM_CONSTRUCT_ONLY property? */
|
||||
sources->priv->registry = e_source_registry_new_sync (NULL, &error);
|
||||
if (error != NULL)
|
||||
{
|
||||
g_error ("%s: %s", G_STRFUNC, error->message);
|
||||
}
|
||||
|
||||
sources->priv->source_added_id = g_signal_connect (sources->priv->registry,
|
||||
"source-added",
|
||||
G_CALLBACK (calendar_sources_registry_source_changed_cb),
|
||||
sources);
|
||||
sources->priv->source_changed_id = g_signal_connect (sources->priv->registry,
|
||||
"source-changed",
|
||||
G_CALLBACK (calendar_sources_registry_source_changed_cb),
|
||||
sources);
|
||||
sources->priv->source_removed_id = g_signal_connect (sources->priv->registry,
|
||||
"source-removed",
|
||||
G_CALLBACK (calendar_sources_registry_source_removed_cb),
|
||||
sources);
|
||||
|
||||
sources->priv->appointment_sources.source_type = E_CAL_CLIENT_SOURCE_TYPE_EVENTS;
|
||||
sources->priv->appointment_sources.sources = sources;
|
||||
sources->priv->appointment_sources.changed_signal = signals [APPOINTMENT_SOURCES_CHANGED];
|
||||
sources->priv->appointment_sources.clients = g_hash_table_new_full ((GHashFunc) e_source_hash,
|
||||
(GEqualFunc) e_source_equal,
|
||||
(GDestroyNotify) g_object_unref,
|
||||
(GDestroyNotify) client_data_free);
|
||||
sources->priv->appointment_sources.timeout_id = 0;
|
||||
|
||||
sources->priv->task_sources.source_type = E_CAL_CLIENT_SOURCE_TYPE_TASKS;
|
||||
sources->priv->task_sources.sources = sources;
|
||||
sources->priv->task_sources.changed_signal = signals [TASK_SOURCES_CHANGED];
|
||||
sources->priv->task_sources.clients = g_hash_table_new_full ((GHashFunc) e_source_hash,
|
||||
(GEqualFunc) e_source_equal,
|
||||
(GDestroyNotify) g_object_unref,
|
||||
(GDestroyNotify) client_data_free);
|
||||
sources->priv->task_sources.timeout_id = 0;
|
||||
|
||||
sources->priv->gconf_client = gconf_client_get_default ();
|
||||
sources->priv->settings = g_settings_new (CALENDAR_SELECTED_SOURCES_SCHEMA);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -195,37 +229,9 @@ calendar_sources_finalize_source_data (CalendarSources *sources,
|
||||
{
|
||||
if (source_data->loaded)
|
||||
{
|
||||
GSList *l;
|
||||
|
||||
if (source_data->selected_sources_handler_id)
|
||||
{
|
||||
g_signal_handler_disconnect (sources->priv->settings,
|
||||
source_data->selected_sources_handler_id);
|
||||
source_data->selected_sources_handler_id = 0;
|
||||
}
|
||||
|
||||
for (l = source_data->clients; l; l = l->next)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (G_OBJECT (l->data),
|
||||
G_CALLBACK (backend_died_cb),
|
||||
source_data);
|
||||
g_object_unref (l->data);
|
||||
}
|
||||
g_slist_free (source_data->clients);
|
||||
g_hash_table_destroy (source_data->clients);
|
||||
source_data->clients = NULL;
|
||||
|
||||
if (source_data->esource_list)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (source_data->esource_list,
|
||||
G_CALLBACK (calendar_sources_esource_list_changed),
|
||||
source_data);
|
||||
g_object_unref (source_data->esource_list);
|
||||
}
|
||||
source_data->esource_list = NULL;
|
||||
|
||||
g_strfreev (source_data->selected_sources);
|
||||
source_data->selected_sources = NULL;
|
||||
|
||||
if (source_data->timeout_id != 0)
|
||||
{
|
||||
g_source_remove (source_data->timeout_id);
|
||||
@ -241,17 +247,21 @@ calendar_sources_finalize (GObject *object)
|
||||
{
|
||||
CalendarSources *sources = CALENDAR_SOURCES (object);
|
||||
|
||||
if (sources->priv->registry)
|
||||
{
|
||||
g_signal_handler_disconnect (sources->priv->registry,
|
||||
sources->priv->source_added_id);
|
||||
g_signal_handler_disconnect (sources->priv->registry,
|
||||
sources->priv->source_changed_id);
|
||||
g_signal_handler_disconnect (sources->priv->registry,
|
||||
sources->priv->source_removed_id);
|
||||
g_object_unref (sources->priv->registry);
|
||||
}
|
||||
sources->priv->registry = NULL;
|
||||
|
||||
calendar_sources_finalize_source_data (sources, &sources->priv->appointment_sources);
|
||||
calendar_sources_finalize_source_data (sources, &sources->priv->task_sources);
|
||||
|
||||
if (sources->priv->gconf_client)
|
||||
g_object_unref (sources->priv->gconf_client);
|
||||
sources->priv->gconf_client = NULL;
|
||||
|
||||
if (sources->priv->settings)
|
||||
g_object_unref (sources->priv->settings);
|
||||
sources->priv->settings = NULL;
|
||||
|
||||
if (G_OBJECT_CLASS (parent_class)->finalize)
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
@ -271,133 +281,72 @@ calendar_sources_get (void)
|
||||
return calendar_sources_singleton;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_source_selected (ESource *esource,
|
||||
char **selected_sources)
|
||||
{
|
||||
const char *uid;
|
||||
char **source;
|
||||
|
||||
uid = e_source_peek_uid (esource);
|
||||
|
||||
for (source = selected_sources; *source; source++)
|
||||
{
|
||||
if (!strcmp (*source, uid))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* The clients are just created here but not loaded */
|
||||
static ECalClient *
|
||||
get_ecal_from_source (ESource *esource,
|
||||
ECalClientSourceType source_type,
|
||||
GSList *existing_clients)
|
||||
static void
|
||||
create_client_for_source (ESource *source,
|
||||
ECalClientSourceType source_type,
|
||||
CalendarSourceData *source_data)
|
||||
{
|
||||
ECalClient *retval;
|
||||
ClientData *data;
|
||||
ECalClient *client;
|
||||
GError *error = NULL;
|
||||
|
||||
if (existing_clients)
|
||||
client = g_hash_table_lookup (source_data->clients, source);
|
||||
g_return_if_fail (client == NULL);
|
||||
|
||||
client = e_cal_client_new (source, source_type, &error);
|
||||
if (!client)
|
||||
{
|
||||
GSList *l;
|
||||
|
||||
for (l = existing_clients; l; l = l->next)
|
||||
{
|
||||
EClient *client = E_CLIENT (l->data);
|
||||
|
||||
if (e_source_equal (esource, e_client_get_source (client)))
|
||||
{
|
||||
dprintf (" load_esource: found existing source ... returning that\n");
|
||||
|
||||
return g_object_ref (client);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
retval = e_cal_client_new (esource, source_type, &error);
|
||||
if (!retval)
|
||||
{
|
||||
g_warning ("Could not load source '%s' from '%s': %s",
|
||||
e_source_peek_name (esource),
|
||||
e_source_peek_relative_uri (esource),
|
||||
g_warning ("Could not load source '%s': %s",
|
||||
e_source_get_uid (source),
|
||||
error->message);
|
||||
g_clear_error(&error);
|
||||
return NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
g_signal_connect (retval, "authenticate",
|
||||
G_CALLBACK (e_client_utils_authenticate_handler), NULL);
|
||||
data = g_slice_new0 (ClientData);
|
||||
data->client = client; /* takes ownership */
|
||||
data->backend_died_id = g_signal_connect (client,
|
||||
"backend-died",
|
||||
G_CALLBACK (backend_died_cb),
|
||||
source_data);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* - Order doesn't matter
|
||||
* - Can just compare object pointers since we
|
||||
* re-use client connections
|
||||
*/
|
||||
static gboolean
|
||||
compare_ecal_lists (GSList *a,
|
||||
GSList *b)
|
||||
{
|
||||
GSList *l;
|
||||
|
||||
if (g_slist_length (a) != g_slist_length (b))
|
||||
return FALSE;
|
||||
|
||||
for (l = a; l; l = l->next)
|
||||
{
|
||||
if (!g_slist_find (b, l->data))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
g_hash_table_insert (source_data->clients, g_object_ref (source), data);
|
||||
}
|
||||
|
||||
static inline void
|
||||
debug_dump_selected_sources (char **selected_sources)
|
||||
debug_dump_ecal_list (GHashTable *clients)
|
||||
{
|
||||
#ifdef CALENDAR_ENABLE_DEBUG
|
||||
char **source;
|
||||
|
||||
dprintf ("Selected sources:\n");
|
||||
for (source = selected_sources; *source; source++)
|
||||
{
|
||||
dprintf (" %s\n", *source);
|
||||
}
|
||||
dprintf ("\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
debug_dump_ecal_list (GSList *ecal_list)
|
||||
{
|
||||
#ifdef CALENDAR_ENABLE_DEBUG
|
||||
GSList *l;
|
||||
GList *list, *link;
|
||||
|
||||
dprintf ("Loaded clients:\n");
|
||||
for (l = ecal_list; l; l = l->next)
|
||||
list = g_hash_table_get_keys (clients);
|
||||
for (link = list; link != NULL; link = g_list_next (link))
|
||||
{
|
||||
EClient *client = l->data;
|
||||
ESource *source = e_client_get_source (client);
|
||||
ESource *source = E_SOURCE (link->data);
|
||||
|
||||
dprintf (" %s %s %s\n",
|
||||
e_source_peek_uid (source),
|
||||
e_source_peek_name (source),
|
||||
e_client_get_uri (client));
|
||||
dprintf (" %s %s\n",
|
||||
e_source_get_uid (source),
|
||||
e_source_get_display_name (source));
|
||||
}
|
||||
g_list_free (list);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
calendar_sources_load_esource_list (CalendarSourceData *source_data);
|
||||
calendar_sources_load_esource_list (ESourceRegistry *registry,
|
||||
CalendarSourceData *source_data);
|
||||
|
||||
static gboolean
|
||||
backend_restart (gpointer data)
|
||||
{
|
||||
CalendarSourceData *source_data = data;
|
||||
ESourceRegistry *registry;
|
||||
|
||||
calendar_sources_load_esource_list (source_data);
|
||||
registry = source_data->sources->priv->registry;
|
||||
calendar_sources_load_esource_list (registry, source_data);
|
||||
g_signal_emit (source_data->sources, source_data->changed_signal, 0);
|
||||
|
||||
source_data->timeout_id = 0;
|
||||
|
||||
@ -407,16 +356,13 @@ backend_restart (gpointer data)
|
||||
static void
|
||||
backend_died_cb (EClient *client, CalendarSourceData *source_data)
|
||||
{
|
||||
const char *uristr;
|
||||
ESource *source;
|
||||
const char *display_name;
|
||||
|
||||
source_data->clients = g_slist_remove (source_data->clients, client);
|
||||
if (g_slist_length (source_data->clients) < 1)
|
||||
{
|
||||
g_slist_free (source_data->clients);
|
||||
source_data->clients = NULL;
|
||||
}
|
||||
uristr = e_client_get_uri (client);
|
||||
g_warning ("The calendar backend for %s has crashed.", uristr);
|
||||
source = e_client_get_source (client);
|
||||
display_name = e_source_get_display_name (source);
|
||||
g_warning ("The calendar backend for '%s' has crashed.", display_name);
|
||||
g_hash_table_remove (source_data->clients, source);
|
||||
|
||||
if (source_data->timeout_id != 0)
|
||||
{
|
||||
@ -429,169 +375,162 @@ backend_died_cb (EClient *client, CalendarSourceData *source_data)
|
||||
}
|
||||
|
||||
static void
|
||||
calendar_sources_load_esource_list (CalendarSourceData *source_data)
|
||||
calendar_sources_load_esource_list (ESourceRegistry *registry,
|
||||
CalendarSourceData *source_data)
|
||||
{
|
||||
GSList *clients = NULL;
|
||||
GSList *groups, *l;
|
||||
gboolean emit_signal = FALSE;
|
||||
GList *list, *link;
|
||||
const gchar *extension_name;
|
||||
|
||||
g_return_if_fail (source_data->esource_list != NULL);
|
||||
|
||||
debug_dump_selected_sources (source_data->selected_sources);
|
||||
|
||||
dprintf ("Source groups:\n");
|
||||
groups = e_source_list_peek_groups (source_data->esource_list);
|
||||
for (l = groups; l; l = l->next)
|
||||
switch (source_data->source_type)
|
||||
{
|
||||
GSList *esources, *s;
|
||||
|
||||
dprintf (" %s\n", e_source_group_peek_uid (l->data));
|
||||
dprintf (" sources:\n");
|
||||
|
||||
esources = e_source_group_peek_sources (l->data);
|
||||
for (s = esources; s; s = s->next)
|
||||
{
|
||||
ESource *esource = E_SOURCE (s->data);
|
||||
ECalClient *client;
|
||||
|
||||
dprintf (" type = '%s' uid = '%s', name = '%s', relative uri = '%s': \n",
|
||||
source_data->source_type == E_CAL_CLIENT_SOURCE_TYPE_EVENTS ? "appointment" : "task",
|
||||
e_source_peek_uid (esource),
|
||||
e_source_peek_name (esource),
|
||||
e_source_peek_relative_uri (esource));
|
||||
|
||||
if (is_source_selected (esource, source_data->selected_sources) &&
|
||||
(client = get_ecal_from_source (esource, source_data->source_type, source_data->clients)))
|
||||
{
|
||||
clients = g_slist_prepend (clients, client);
|
||||
}
|
||||
}
|
||||
}
|
||||
dprintf ("\n");
|
||||
|
||||
if (source_data->loaded &&
|
||||
!compare_ecal_lists (source_data->clients, clients))
|
||||
emit_signal = TRUE;
|
||||
|
||||
for (l = source_data->clients; l; l = l->next)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (G_OBJECT (l->data),
|
||||
G_CALLBACK (backend_died_cb),
|
||||
source_data);
|
||||
|
||||
g_object_unref (l->data);
|
||||
}
|
||||
g_slist_free (source_data->clients);
|
||||
source_data->clients = g_slist_reverse (clients);
|
||||
|
||||
/* connect to backend_died after we disconnected the previous signal
|
||||
* handlers. If we do it before, we'll lose some handlers (for clients that
|
||||
* were already there before) */
|
||||
for (l = source_data->clients; l; l = l->next)
|
||||
{
|
||||
g_signal_connect (G_OBJECT (l->data), "backend-died",
|
||||
G_CALLBACK (backend_died_cb), source_data);
|
||||
case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
|
||||
extension_name = E_SOURCE_EXTENSION_CALENDAR;
|
||||
break;
|
||||
case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
|
||||
extension_name = E_SOURCE_EXTENSION_TASK_LIST;
|
||||
break;
|
||||
default:
|
||||
g_return_if_reached ();
|
||||
}
|
||||
|
||||
if (emit_signal)
|
||||
list = e_source_registry_list_sources (registry, extension_name);
|
||||
|
||||
for (link = list; link != NULL; link = g_list_next (link))
|
||||
{
|
||||
dprintf ("Emitting %s-sources-changed signal\n",
|
||||
source_data->source_type == E_CAL_CLIENT_SOURCE_TYPE_EVENTS ? "appointment" : "task");
|
||||
g_signal_emit (source_data->sources, source_data->changed_signal, 0);
|
||||
ESource *source = E_SOURCE (link->data);
|
||||
ESourceSelectable *extension;
|
||||
gboolean show_source;
|
||||
|
||||
extension = e_source_get_extension (source, extension_name);
|
||||
show_source = e_source_get_enabled (source) && e_source_selectable_get_selected (extension);
|
||||
|
||||
if (show_source)
|
||||
create_client_for_source (source, source_data->source_type, source_data);
|
||||
}
|
||||
|
||||
debug_dump_ecal_list (source_data->clients);
|
||||
|
||||
g_list_free_full (list, g_object_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
calendar_sources_esource_list_changed (ESourceList *source_list,
|
||||
CalendarSourceData *source_data)
|
||||
|
||||
calendar_sources_registry_source_changed_cb (ESourceRegistry *registry,
|
||||
ESource *source,
|
||||
CalendarSources *sources)
|
||||
{
|
||||
dprintf ("ESourceList changed, reloading\n");
|
||||
if (e_source_has_extension (source, E_SOURCE_EXTENSION_CALENDAR))
|
||||
{
|
||||
CalendarSourceData *source_data;
|
||||
ESourceSelectable *extension;
|
||||
gboolean have_client;
|
||||
gboolean show_source;
|
||||
|
||||
calendar_sources_load_esource_list (source_data);
|
||||
source_data = &sources->priv->appointment_sources;
|
||||
extension = e_source_get_extension (source, E_SOURCE_EXTENSION_CALENDAR);
|
||||
have_client = (g_hash_table_lookup (source_data->clients, source) != NULL);
|
||||
show_source = e_source_get_enabled (source) && e_source_selectable_get_selected (extension);
|
||||
|
||||
if (!show_source && have_client)
|
||||
{
|
||||
g_hash_table_remove (source_data->clients, source);
|
||||
g_signal_emit (sources, source_data->changed_signal, 0);
|
||||
}
|
||||
if (show_source && !have_client)
|
||||
{
|
||||
create_client_for_source (source, source_data->source_type, source_data);
|
||||
g_signal_emit (sources, source_data->changed_signal, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (e_source_has_extension (source, E_SOURCE_EXTENSION_TASK_LIST))
|
||||
{
|
||||
CalendarSourceData *source_data;
|
||||
ESourceSelectable *extension;
|
||||
gboolean have_client;
|
||||
gboolean show_source;
|
||||
|
||||
source_data = &sources->priv->task_sources;
|
||||
extension = e_source_get_extension (source, E_SOURCE_EXTENSION_TASK_LIST);
|
||||
have_client = (g_hash_table_lookup (source_data->clients, source) != NULL);
|
||||
show_source = e_source_get_enabled (source) && e_source_selectable_get_selected (extension);
|
||||
|
||||
if (!show_source && have_client)
|
||||
{
|
||||
g_hash_table_remove (source_data->clients, source);
|
||||
g_signal_emit (sources, source_data->changed_signal, 0);
|
||||
}
|
||||
if (show_source && !have_client)
|
||||
{
|
||||
create_client_for_source (source, source_data->source_type, source_data);
|
||||
g_signal_emit (sources, source_data->changed_signal, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
calendar_sources_selected_sources_notify (GSettings *settings,
|
||||
const gchar *key,
|
||||
CalendarSourceData *source_data)
|
||||
calendar_sources_registry_source_removed_cb (ESourceRegistry *registry,
|
||||
ESource *source,
|
||||
CalendarSources *sources)
|
||||
{
|
||||
dprintf ("Selected sources key (%s) changed, reloading\n", key);
|
||||
if (e_source_has_extension (source, E_SOURCE_EXTENSION_CALENDAR))
|
||||
{
|
||||
CalendarSourceData *source_data;
|
||||
|
||||
g_strfreev (source_data->selected_sources);
|
||||
source_data->selected_sources = g_settings_get_strv (settings, key);
|
||||
source_data = &sources->priv->appointment_sources;
|
||||
g_hash_table_remove (source_data->clients, source);
|
||||
g_signal_emit (sources, source_data->changed_signal, 0);
|
||||
}
|
||||
|
||||
calendar_sources_load_esource_list (source_data);
|
||||
if (e_source_has_extension (source, E_SOURCE_EXTENSION_TASK_LIST))
|
||||
{
|
||||
CalendarSourceData *source_data;
|
||||
|
||||
source_data = &sources->priv->task_sources;
|
||||
g_hash_table_remove (source_data->clients, source);
|
||||
g_signal_emit (sources, source_data->changed_signal, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
calendar_sources_load_sources (CalendarSources *sources,
|
||||
CalendarSourceData *source_data,
|
||||
const char *sources_key,
|
||||
const char *selected_sources_key)
|
||||
GList *
|
||||
calendar_sources_get_appointment_clients (CalendarSources *sources)
|
||||
{
|
||||
GConfClient *gconf_client;
|
||||
GSettings *settings;
|
||||
char *signal_name;
|
||||
GList *list, *link;
|
||||
|
||||
dprintf ("---------------------------\n");
|
||||
dprintf ("Loading sources:\n");
|
||||
dprintf (" sources_key: %s\n", sources_key);
|
||||
dprintf (" selected_sources_key: %s\n", selected_sources_key);
|
||||
|
||||
gconf_client = sources->priv->gconf_client;
|
||||
settings = sources->priv->settings;
|
||||
|
||||
source_data->selected_sources = g_settings_get_strv (settings, selected_sources_key);
|
||||
|
||||
signal_name = g_strconcat ("changed::", selected_sources_key, NULL);
|
||||
source_data->selected_sources_handler_id =
|
||||
g_signal_connect (settings, signal_name,
|
||||
G_CALLBACK (calendar_sources_selected_sources_notify), source_data);
|
||||
g_free (signal_name);
|
||||
|
||||
source_data->esource_list = e_source_list_new_for_gconf (gconf_client, sources_key);
|
||||
g_signal_connect (source_data->esource_list, "changed",
|
||||
G_CALLBACK (calendar_sources_esource_list_changed),
|
||||
source_data);
|
||||
|
||||
calendar_sources_load_esource_list (source_data);
|
||||
|
||||
source_data->loaded = TRUE;
|
||||
|
||||
dprintf ("---------------------------\n");
|
||||
}
|
||||
|
||||
GSList *
|
||||
calendar_sources_get_appointment_sources (CalendarSources *sources)
|
||||
{
|
||||
g_return_val_if_fail (CALENDAR_IS_SOURCES (sources), NULL);
|
||||
|
||||
if (!sources->priv->appointment_sources.loaded)
|
||||
{
|
||||
calendar_sources_load_sources (sources,
|
||||
&sources->priv->appointment_sources,
|
||||
CALENDAR_SOURCES_APPOINTMENT_SOURCES_KEY,
|
||||
CALENDAR_SOURCES_SELECTED_APPOINTMENT_SOURCES_KEY);
|
||||
calendar_sources_load_esource_list (sources->priv->registry,
|
||||
&sources->priv->appointment_sources);
|
||||
sources->priv->appointment_sources.loaded = TRUE;
|
||||
}
|
||||
|
||||
return sources->priv->appointment_sources.clients;
|
||||
|
||||
list = g_hash_table_get_values (sources->priv->appointment_sources.clients);
|
||||
|
||||
for (link = list; link != NULL; link = g_list_next (link))
|
||||
link->data = ((ClientData *) link->data)->client;
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
GSList *
|
||||
calendar_sources_get_task_sources (CalendarSources *sources)
|
||||
GList *
|
||||
calendar_sources_get_task_clients (CalendarSources *sources)
|
||||
{
|
||||
GList *list, *link;
|
||||
|
||||
g_return_val_if_fail (CALENDAR_IS_SOURCES (sources), NULL);
|
||||
|
||||
if (!sources->priv->task_sources.loaded)
|
||||
{
|
||||
calendar_sources_load_sources (sources,
|
||||
&sources->priv->task_sources,
|
||||
CALENDAR_SOURCES_TASK_SOURCES_KEY,
|
||||
CALENDAR_SOURCES_SELECTED_TASK_SOURCES_KEY);
|
||||
calendar_sources_load_esource_list (sources->priv->registry,
|
||||
&sources->priv->task_sources);
|
||||
sources->priv->task_sources.loaded = TRUE;
|
||||
}
|
||||
|
||||
return sources->priv->task_sources.clients;
|
||||
list = g_hash_table_get_values (sources->priv->task_sources.clients);
|
||||
|
||||
for (link = list; link != NULL; link = g_list_next (link))
|
||||
link->data = ((ClientData *) link->data)->client;
|
||||
|
||||
return list;
|
||||
}
|
||||
|
@ -58,8 +58,8 @@ struct _CalendarSourcesClass
|
||||
|
||||
GType calendar_sources_get_type (void) G_GNUC_CONST;
|
||||
CalendarSources *calendar_sources_get (void);
|
||||
GSList *calendar_sources_get_appointment_sources (CalendarSources *sources);
|
||||
GSList *calendar_sources_get_task_sources (CalendarSources *sources);
|
||||
GList *calendar_sources_get_appointment_clients (CalendarSources *sources);
|
||||
GList *calendar_sources_get_task_clients (CalendarSources *sources);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@ -37,13 +37,7 @@
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define HANDLE_LIBICAL_MEMORY
|
||||
#include <libecal/e-cal-client.h>
|
||||
#include <libecal/e-cal-time-util.h>
|
||||
#include <libecal/e-cal-recur.h>
|
||||
#include <libecal/e-cal-system-timezone.h>
|
||||
|
||||
#define CALENDAR_CONFIG_PREFIX "/apps/evolution/calendar"
|
||||
#define CALENDAR_CONFIG_TIMEZONE CALENDAR_CONFIG_PREFIX "/display/timezone"
|
||||
#include <libecal/libecal.h>
|
||||
|
||||
#include "calendar-sources.h"
|
||||
|
||||
@ -90,7 +84,7 @@ typedef struct
|
||||
{
|
||||
char *uid;
|
||||
char *rid;
|
||||
char *uri;
|
||||
char *backend_name;
|
||||
char *summary;
|
||||
char *description;
|
||||
char *color_string;
|
||||
@ -253,37 +247,60 @@ static char *
|
||||
get_source_color (ECalClient *esource)
|
||||
{
|
||||
ESource *source;
|
||||
ECalClientSourceType source_type;
|
||||
ESourceSelectable *extension;
|
||||
const gchar *extension_name;
|
||||
|
||||
g_return_val_if_fail (E_IS_CAL_CLIENT (esource), NULL);
|
||||
|
||||
source = e_client_get_source (E_CLIENT (esource));
|
||||
source_type = e_cal_client_get_source_type (esource);
|
||||
|
||||
return g_strdup (e_source_peek_color_spec (source));
|
||||
switch (source_type)
|
||||
{
|
||||
case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
|
||||
extension_name = E_SOURCE_EXTENSION_CALENDAR;
|
||||
break;
|
||||
case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
|
||||
extension_name = E_SOURCE_EXTENSION_TASK_LIST;
|
||||
break;
|
||||
default:
|
||||
g_return_val_if_reached (NULL);
|
||||
}
|
||||
|
||||
extension = e_source_get_extension (source, extension_name);
|
||||
|
||||
return e_source_selectable_dup_color (extension);
|
||||
}
|
||||
|
||||
static gchar *
|
||||
get_source_uri (ECalClient *esource)
|
||||
get_source_backend_name (ECalClient *esource)
|
||||
{
|
||||
ESource *source;
|
||||
gchar *string;
|
||||
gchar **list;
|
||||
ESource *source;
|
||||
ECalClientSourceType source_type;
|
||||
ESourceBackend *extension;
|
||||
const gchar *extension_name;
|
||||
|
||||
g_return_val_if_fail (E_IS_CAL_CLIENT (esource), NULL);
|
||||
g_return_val_if_fail (E_IS_CAL_CLIENT (esource), NULL);
|
||||
|
||||
source = e_client_get_source (E_CLIENT (esource));
|
||||
string = g_strdup (e_source_get_uri (source));
|
||||
if (string) {
|
||||
list = g_strsplit (string, ":", 2);
|
||||
g_free (string);
|
||||
source = e_client_get_source (E_CLIENT (esource));
|
||||
source_type = e_cal_client_get_source_type (esource);
|
||||
|
||||
if (list[0]) {
|
||||
string = g_strdup (list[0]);
|
||||
g_strfreev (list);
|
||||
return string;
|
||||
}
|
||||
g_strfreev (list);
|
||||
switch (source_type)
|
||||
{
|
||||
case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
|
||||
extension_name = E_SOURCE_EXTENSION_CALENDAR;
|
||||
break;
|
||||
case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
|
||||
extension_name = E_SOURCE_EXTENSION_TASK_LIST;
|
||||
break;
|
||||
default:
|
||||
g_return_val_if_reached (NULL);
|
||||
}
|
||||
return NULL;
|
||||
|
||||
extension = e_source_get_extension (source, extension_name);
|
||||
|
||||
return e_source_backend_dup_backend_name (extension);
|
||||
}
|
||||
|
||||
static inline int
|
||||
@ -314,7 +331,7 @@ calendar_appointment_equal (CalendarAppointment *a,
|
||||
|
||||
return
|
||||
null_safe_strcmp (a->uid, b->uid) == 0 &&
|
||||
null_safe_strcmp (a->uri, b->uri) == 0 &&
|
||||
null_safe_strcmp (a->backend_name, b->backend_name) == 0 &&
|
||||
null_safe_strcmp (a->summary, b->summary) == 0 &&
|
||||
null_safe_strcmp (a->description, b->description) == 0 &&
|
||||
null_safe_strcmp (a->color_string, b->color_string) == 0 &&
|
||||
@ -339,8 +356,8 @@ calendar_appointment_free (CalendarAppointment *appointment)
|
||||
g_free (appointment->rid);
|
||||
appointment->rid = NULL;
|
||||
|
||||
g_free (appointment->uri);
|
||||
appointment->uri = NULL;
|
||||
g_free (appointment->backend_name);
|
||||
appointment->backend_name = NULL;
|
||||
|
||||
g_free (appointment->summary);
|
||||
appointment->summary = NULL;
|
||||
@ -363,7 +380,7 @@ calendar_appointment_init (CalendarAppointment *appointment,
|
||||
{
|
||||
appointment->uid = get_ical_uid (ical);
|
||||
appointment->rid = get_ical_rid (ical);
|
||||
appointment->uri = get_source_uri (cal);
|
||||
appointment->backend_name = get_source_backend_name (cal);
|
||||
appointment->summary = get_ical_summary (ical);
|
||||
appointment->description = get_ical_description (ical);
|
||||
appointment->color_string = get_source_color (cal);
|
||||
@ -467,9 +484,6 @@ struct _App
|
||||
CalendarSources *sources;
|
||||
gulong sources_signal_id;
|
||||
|
||||
guint zone_listener;
|
||||
GConfClient *gconf_client;
|
||||
|
||||
/* hash from uid to CalendarAppointment objects */
|
||||
GHashTable *appointments;
|
||||
|
||||
@ -585,8 +599,8 @@ on_objects_removed (ECalClientView *view,
|
||||
static void
|
||||
app_load_events (App *app)
|
||||
{
|
||||
GSList *sources;
|
||||
GSList *l;
|
||||
GList *clients;
|
||||
GList *l;
|
||||
GList *ll;
|
||||
gchar *since_iso8601;
|
||||
gchar *until_iso8601;
|
||||
@ -616,8 +630,8 @@ app_load_events (App *app)
|
||||
since_iso8601,
|
||||
until_iso8601);
|
||||
|
||||
sources = calendar_sources_get_appointment_sources (app->sources);
|
||||
for (l = sources; l != NULL; l = l->next)
|
||||
clients = calendar_sources_get_appointment_clients (app->sources);
|
||||
for (l = clients; l != NULL; l = l->next)
|
||||
{
|
||||
ECalClient *cal = E_CAL_CLIENT (l->data);
|
||||
GError *error;
|
||||
@ -630,8 +644,9 @@ app_load_events (App *app)
|
||||
error = NULL;
|
||||
if (!e_client_open_sync (E_CLIENT (cal), TRUE, NULL, &error))
|
||||
{
|
||||
ESource *source = e_client_get_source (E_CLIENT (cal));
|
||||
g_warning ("Error opening calendar %s: %s\n",
|
||||
e_client_get_uri (E_CLIENT (cal)), error->message);
|
||||
e_source_get_uid (source), error->message);
|
||||
g_error_free (error);
|
||||
continue;
|
||||
}
|
||||
@ -648,8 +663,9 @@ app_load_events (App *app)
|
||||
NULL, /* cancellable */
|
||||
&error))
|
||||
{
|
||||
ESource *source = e_client_get_source (E_CLIENT (cal));
|
||||
g_warning ("Error querying calendar %s: %s\n",
|
||||
e_client_get_uri (E_CLIENT (cal)), error->message);
|
||||
e_source_get_uid (source), error->message);
|
||||
g_error_free (error);
|
||||
g_free (query);
|
||||
continue;
|
||||
@ -705,6 +721,7 @@ app_load_events (App *app)
|
||||
|
||||
g_free (query);
|
||||
}
|
||||
g_list_free (clients);
|
||||
g_free (since_iso8601);
|
||||
g_free (until_iso8601);
|
||||
app->cache_invalid = FALSE;
|
||||
|
20
src/main.c
20
src/main.c
@ -18,10 +18,10 @@
|
||||
#include <meta/main.h>
|
||||
#include <meta/meta-plugin.h>
|
||||
#include <meta/prefs.h>
|
||||
#include <atk-bridge.h>
|
||||
#include <telepathy-glib/debug.h>
|
||||
#include <telepathy-glib/debug-sender.h>
|
||||
|
||||
#include "shell-a11y.h"
|
||||
#include "shell-global.h"
|
||||
#include "shell-global-private.h"
|
||||
#include "shell-js.h"
|
||||
@ -235,6 +235,20 @@ shell_perf_log_init (void)
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_a11y_init (void)
|
||||
{
|
||||
if (clutter_get_accessibility_enabled () == FALSE)
|
||||
{
|
||||
g_warning ("Accessibility: clutter has no accessibility enabled"
|
||||
" skipping the atk-bridge load");
|
||||
}
|
||||
else
|
||||
{
|
||||
atk_bridge_adaptor_init (NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
default_log_handler (const char *log_domain,
|
||||
GLogLevelFlags log_level,
|
||||
@ -358,13 +372,11 @@ main (int argc, char **argv)
|
||||
|
||||
g_option_context_free (ctx);
|
||||
|
||||
meta_plugin_type_register (gnome_shell_plugin_get_type ());
|
||||
meta_plugin_manager_set_plugin_type (gnome_shell_plugin_get_type ());
|
||||
|
||||
/* Prevent meta_init() from causing gtk to load gail and at-bridge */
|
||||
g_setenv ("NO_GAIL", "1", TRUE);
|
||||
g_setenv ("NO_AT_BRIDGE", "1", TRUE);
|
||||
meta_init ();
|
||||
g_unsetenv ("NO_GAIL");
|
||||
g_unsetenv ("NO_AT_BRIDGE");
|
||||
|
||||
/* FIXME: Add gjs API to set this stuff and don't depend on the
|
||||
|
@ -144,6 +144,9 @@ main(int argc, char **argv)
|
||||
exit (1);
|
||||
}
|
||||
|
||||
gjs_context_gc (js_context);
|
||||
gjs_context_gc (js_context);
|
||||
|
||||
g_free (script);
|
||||
exit (code);
|
||||
}
|
||||
|
164
src/shell-a11y.c
164
src/shell-a11y.c
@ -1,164 +0,0 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
/*
|
||||
* Copyright (C) 2010 Igalia, S.L.
|
||||
*
|
||||
* Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <gmodule.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include "shell-a11y.h"
|
||||
|
||||
#define INIT_METHOD "gnome_accessibility_module_init"
|
||||
#define DESKTOP_SCHEMA "org.gnome.desktop.interface"
|
||||
#define ACCESSIBILITY_ENABLED_KEY "toolkit-accessibility"
|
||||
#define AT_SPI_SCHEMA "org.a11y.atspi"
|
||||
#define ATK_BRIDGE_LOCATION_KEY "atk-bridge-location"
|
||||
|
||||
static gboolean
|
||||
should_enable_a11y (void)
|
||||
{
|
||||
GSettings *desktop_settings = NULL;
|
||||
gboolean value = FALSE;
|
||||
|
||||
desktop_settings = g_settings_new (DESKTOP_SCHEMA);
|
||||
value = g_settings_get_boolean (desktop_settings, ACCESSIBILITY_ENABLED_KEY);
|
||||
|
||||
g_object_unref (desktop_settings);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static char*
|
||||
get_atk_bridge_path (void)
|
||||
{
|
||||
GSettings *atspi_settings = NULL;
|
||||
GVariant *variant = NULL;
|
||||
char *value = NULL;
|
||||
const char * const *schemas = NULL;
|
||||
gboolean found = FALSE;
|
||||
int i = 0;
|
||||
|
||||
schemas = g_settings_list_schemas ();
|
||||
|
||||
for (i = 0; schemas [i]; i++)
|
||||
{
|
||||
if (!strcmp (schemas[i], AT_SPI_SCHEMA))
|
||||
{
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
g_warning ("Accessibility: %s schema not found. Are you sure that at-spi or"
|
||||
" at-spi2 is installed on your system?", AT_SPI_SCHEMA);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
atspi_settings = g_settings_new (AT_SPI_SCHEMA);
|
||||
variant = g_settings_get_value (atspi_settings, ATK_BRIDGE_LOCATION_KEY);
|
||||
value = g_variant_dup_bytestring (variant, NULL);
|
||||
g_variant_unref (variant);
|
||||
g_object_unref (atspi_settings);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
a11y_invoke_module (const char *module_path)
|
||||
{
|
||||
GModule *handle;
|
||||
void (*invoke_fn) (void);
|
||||
|
||||
if (!module_path)
|
||||
{
|
||||
g_warning ("Accessibility: invalid module path (NULL)");
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!(handle = g_module_open (module_path, 0)))
|
||||
{
|
||||
g_warning ("Accessibility: failed to load module '%s': '%s'",
|
||||
module_path, g_module_error ());
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!g_module_symbol (handle, INIT_METHOD, (gpointer *)&invoke_fn))
|
||||
{
|
||||
g_warning ("Accessibility: error library '%s' does not include "
|
||||
"method '%s' required for accessibility support",
|
||||
module_path, INIT_METHOD);
|
||||
g_module_close (handle);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
invoke_fn ();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* It loads the atk-bridge if required. It checks:
|
||||
* * If the proper gsetting key is set
|
||||
* * If clutter has already enabled the accessibility
|
||||
*
|
||||
* You need to ensure that the atk-bridge was not loaded before this
|
||||
* call, because in that case the application would be already
|
||||
* registered on at-spi using the AtkUtil implementation on that
|
||||
* moment (if any, although without anyone the application would
|
||||
* crash). Anyway this is the reason of NO_AT_BRIDGE.
|
||||
*
|
||||
*/
|
||||
void
|
||||
shell_a11y_init (void)
|
||||
{
|
||||
char *bridge_path = NULL;
|
||||
|
||||
if (!should_enable_a11y ())
|
||||
return;
|
||||
|
||||
if (clutter_get_accessibility_enabled () == FALSE)
|
||||
{
|
||||
g_warning ("Accessibility: clutter has no accessibility enabled"
|
||||
" skipping the atk-bridge load");
|
||||
return;
|
||||
}
|
||||
|
||||
bridge_path = get_atk_bridge_path ();
|
||||
|
||||
if (a11y_invoke_module (bridge_path) == FALSE)
|
||||
{
|
||||
g_warning ("Accessibility: error loading the atk-bridge. Although the"
|
||||
" accessibility on the system is enabled and clutter"
|
||||
" accessibility is also enabled, accessibility support on"
|
||||
" GNOME Shell will not work");
|
||||
}
|
||||
|
||||
/* NOTE: We avoid to load gail module, as gail-cally interaction is
|
||||
* not fully supported right now.
|
||||
*/
|
||||
|
||||
g_free (bridge_path);
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
/*
|
||||
* Copyright (C) 2010 Igalia, S.L.
|
||||
*
|
||||
* Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SHELL_A11Y_H_
|
||||
#define __SHELL_A11Y_H_
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
void shell_a11y_init (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __SHELL_A11Y_H_ */
|
@ -7,18 +7,13 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <gio/gdesktopappinfo.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <clutter/clutter.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <meta/display.h>
|
||||
|
||||
#include "shell-app-private.h"
|
||||
#include "shell-window-tracker-private.h"
|
||||
#include "shell-app-system-private.h"
|
||||
#include "shell-global.h"
|
||||
#include "shell-util.h"
|
||||
#include "st.h"
|
||||
|
||||
/* Vendor prefixes are something that can be preprended to a .desktop
|
||||
* file name. Undo this.
|
||||
@ -46,6 +41,7 @@ struct _ShellAppSystemPrivate {
|
||||
GMenuTree *apps_tree;
|
||||
|
||||
GHashTable *running_apps;
|
||||
GHashTable *visible_id_to_app;
|
||||
GHashTable *id_to_app;
|
||||
|
||||
GSList *known_vendor_prefixes;
|
||||
@ -97,14 +93,16 @@ shell_app_system_init (ShellAppSystem *self)
|
||||
priv->id_to_app = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
NULL,
|
||||
(GDestroyNotify)g_object_unref);
|
||||
|
||||
/* All the objects in this hash table are owned by id_to_app */
|
||||
priv->visible_id_to_app = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
|
||||
priv->setting_id_to_app = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
NULL,
|
||||
(GDestroyNotify)g_object_unref);
|
||||
|
||||
/* For now, we want to pick up Evince, Nautilus, etc. We'll
|
||||
* handle NODISPLAY semantics at a higher level or investigate them
|
||||
* case by case.
|
||||
*/
|
||||
/* We want to track NoDisplay apps, so we add INCLUDE_NODISPLAY. We'll
|
||||
* filter NoDisplay apps out when showing them to the user. */
|
||||
priv->apps_tree = gmenu_tree_new ("applications.menu", GMENU_TREE_FLAGS_INCLUDE_NODISPLAY);
|
||||
g_signal_connect (priv->apps_tree, "changed", G_CALLBACK (on_apps_tree_changed_cb), self);
|
||||
|
||||
@ -126,10 +124,10 @@ shell_app_system_finalize (GObject *object)
|
||||
|
||||
g_hash_table_destroy (priv->running_apps);
|
||||
g_hash_table_destroy (priv->id_to_app);
|
||||
g_hash_table_destroy (priv->visible_id_to_app);
|
||||
g_hash_table_destroy (priv->setting_id_to_app);
|
||||
|
||||
g_slist_foreach (priv->known_vendor_prefixes, (GFunc)g_free, NULL);
|
||||
g_slist_free (priv->known_vendor_prefixes);
|
||||
g_slist_free_full (priv->known_vendor_prefixes, g_free);
|
||||
priv->known_vendor_prefixes = NULL;
|
||||
|
||||
G_OBJECT_CLASS (shell_app_system_parent_class)->finalize (object);
|
||||
@ -314,8 +312,8 @@ on_apps_tree_changed_cb (GMenuTree *tree,
|
||||
|
||||
g_assert (tree == self->priv->apps_tree);
|
||||
|
||||
g_slist_foreach (self->priv->known_vendor_prefixes, (GFunc)g_free, NULL);
|
||||
g_slist_free (self->priv->known_vendor_prefixes);
|
||||
g_hash_table_remove_all (self->priv->visible_id_to_app);
|
||||
g_slist_free_full (self->priv->known_vendor_prefixes, g_free);
|
||||
self->priv->known_vendor_prefixes = NULL;
|
||||
|
||||
if (!gmenu_tree_load_sync (self->priv->apps_tree, &error))
|
||||
@ -376,6 +374,8 @@ on_apps_tree_changed_cb (GMenuTree *tree,
|
||||
* string is pointed to.
|
||||
*/
|
||||
g_hash_table_replace (self->priv->id_to_app, (char*)id, app);
|
||||
if (!gmenu_tree_entry_get_is_nodisplay_recurse (entry))
|
||||
g_hash_table_replace (self->priv->visible_id_to_app, (char*)id, app);
|
||||
|
||||
if (old_entry)
|
||||
gmenu_tree_item_unref (old_entry);
|
||||
@ -644,30 +644,6 @@ shell_app_system_lookup_wmclass (ShellAppSystem *system,
|
||||
return app;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_app_system_get_all:
|
||||
* @system:
|
||||
*
|
||||
* Returns: (transfer container) (element-type ShellApp): All installed applications
|
||||
*/
|
||||
GSList *
|
||||
shell_app_system_get_all (ShellAppSystem *self)
|
||||
{
|
||||
GSList *result = NULL;
|
||||
GHashTableIter iter;
|
||||
gpointer key, value;
|
||||
|
||||
g_hash_table_iter_init (&iter, self->priv->id_to_app);
|
||||
while (g_hash_table_iter_next (&iter, &key, &value))
|
||||
{
|
||||
ShellApp *app = value;
|
||||
|
||||
if (!g_desktop_app_info_get_nodisplay (shell_app_get_app_info (app)))
|
||||
result = g_slist_prepend (result, app);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
_shell_app_system_notify_app_state_changed (ShellAppSystem *self,
|
||||
ShellApp *app)
|
||||
@ -790,8 +766,7 @@ search_tree (ShellAppSystem *self,
|
||||
&prefix_results,
|
||||
&substring_results);
|
||||
}
|
||||
g_slist_foreach (normalized_terms, (GFunc)g_free, NULL);
|
||||
g_slist_free (normalized_terms);
|
||||
g_slist_free_full (normalized_terms, g_free);
|
||||
|
||||
return sort_and_concat_results (self, prefix_results, substring_results);
|
||||
|
||||
@ -810,7 +785,7 @@ GSList *
|
||||
shell_app_system_initial_search (ShellAppSystem *self,
|
||||
GSList *terms)
|
||||
{
|
||||
return search_tree (self, terms, self->priv->id_to_app);
|
||||
return search_tree (self, terms, self->priv->visible_id_to_app);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -844,8 +819,7 @@ shell_app_system_subsearch (ShellAppSystem *system,
|
||||
&prefix_results,
|
||||
&substring_results);
|
||||
}
|
||||
g_slist_foreach (normalized_terms, (GFunc)g_free, NULL);
|
||||
g_slist_free (normalized_terms);
|
||||
g_slist_free_full (normalized_terms, g_free);
|
||||
|
||||
/* Note that a shorter term might have matched as a prefix, but
|
||||
when extended only as a substring, so we have to redo the
|
||||
|
@ -52,8 +52,6 @@ ShellApp *shell_app_system_lookup_heuristic_basename (ShellAppSystem *
|
||||
ShellApp *shell_app_system_lookup_wmclass (ShellAppSystem *system,
|
||||
const char *wmclass);
|
||||
|
||||
GSList *shell_app_system_get_all (ShellAppSystem *system);
|
||||
|
||||
GSList *shell_app_system_get_running (ShellAppSystem *self);
|
||||
|
||||
GSList *shell_app_system_initial_search (ShellAppSystem *system,
|
||||
|
@ -42,6 +42,7 @@ typedef struct {
|
||||
/* See GApplication documentation */
|
||||
GDBusMenuModel *remote_menu;
|
||||
GActionMuxer *muxer;
|
||||
char * unique_bus_name;
|
||||
} ShellAppRunningState;
|
||||
|
||||
/**
|
||||
@ -95,7 +96,6 @@ enum {
|
||||
static guint shell_app_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static void create_running_state (ShellApp *app);
|
||||
static void setup_running_state (ShellApp *app, MetaWindow *window);
|
||||
static void unref_running_state (ShellAppRunningState *state);
|
||||
|
||||
G_DEFINE_TYPE (ShellApp, shell_app, G_TYPE_OBJECT)
|
||||
@ -975,7 +975,7 @@ _shell_app_add_window (ShellApp *app,
|
||||
g_signal_connect (window, "unmanaged", G_CALLBACK(shell_app_on_unmanaged), app);
|
||||
g_signal_connect (window, "notify::user-time", G_CALLBACK(shell_app_on_user_time_changed), app);
|
||||
|
||||
setup_running_state (app, window);
|
||||
shell_app_update_app_menu (app, window);
|
||||
|
||||
if (app->state != SHELL_APP_STATE_STARTING)
|
||||
shell_app_state_transition (app, SHELL_APP_STATE_RUNNING);
|
||||
@ -1221,12 +1221,14 @@ create_running_state (ShellApp *app)
|
||||
app->running_state->muxer = g_action_muxer_new ();
|
||||
}
|
||||
|
||||
static void
|
||||
setup_running_state (ShellApp *app,
|
||||
MetaWindow *window)
|
||||
void
|
||||
shell_app_update_app_menu (ShellApp *app,
|
||||
MetaWindow *window)
|
||||
{
|
||||
/* We assume that 'gtk-unique-bus-name', gtk-application-object-path'
|
||||
* and 'gtk-app-menu-object-path' are the same for all windows which
|
||||
const gchar *unique_bus_name;
|
||||
|
||||
/* We assume that 'gtk-application-object-path' and
|
||||
* 'gtk-app-menu-object-path' are the same for all windows which
|
||||
* have it set.
|
||||
*
|
||||
* It could be possible, however, that the first window we see
|
||||
@ -1235,23 +1237,27 @@ setup_running_state (ShellApp *app,
|
||||
* all the rest (until the app is stopped and restarted).
|
||||
*/
|
||||
|
||||
if (app->running_state->remote_menu == NULL)
|
||||
unique_bus_name = meta_window_get_gtk_unique_bus_name (window);
|
||||
|
||||
if (app->running_state->remote_menu == NULL ||
|
||||
g_strcmp0 (app->running_state->unique_bus_name, unique_bus_name) != 0)
|
||||
{
|
||||
const gchar *application_object_path;
|
||||
const gchar *app_menu_object_path;
|
||||
const gchar *unique_bus_name;
|
||||
GDBusConnection *session;
|
||||
GDBusActionGroup *actions;
|
||||
|
||||
application_object_path = meta_window_get_gtk_application_object_path (window);
|
||||
app_menu_object_path = meta_window_get_gtk_app_menu_object_path (window);
|
||||
unique_bus_name = meta_window_get_gtk_unique_bus_name (window);
|
||||
|
||||
if (application_object_path == NULL || app_menu_object_path == NULL || unique_bus_name == NULL)
|
||||
return;
|
||||
|
||||
session = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
|
||||
g_assert (session != NULL);
|
||||
g_clear_pointer (&app->running_state->unique_bus_name, g_free);
|
||||
app->running_state->unique_bus_name = g_strdup (unique_bus_name);
|
||||
g_clear_object (&app->running_state->remote_menu);
|
||||
app->running_state->remote_menu = g_dbus_menu_model_get (session, unique_bus_name, app_menu_object_path);
|
||||
actions = g_dbus_action_group_get (session, unique_bus_name, application_object_path);
|
||||
g_action_muxer_insert (app->running_state->muxer, "app", G_ACTION_GROUP (actions));
|
||||
|
@ -82,6 +82,7 @@ int shell_app_compare_by_name (ShellApp *app, ShellApp *other);
|
||||
int shell_app_compare (ShellApp *app, ShellApp *other);
|
||||
|
||||
void shell_app_update_window_actions (ShellApp *app, MetaWindow *window);
|
||||
void shell_app_update_app_menu (ShellApp *app, MetaWindow *window);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@ -297,7 +297,7 @@ sort_and_prepare_results (GSList *results)
|
||||
sorted_results = g_slist_prepend (sorted_results, id);
|
||||
}
|
||||
|
||||
g_slist_foreach (results, (GFunc) free_result, NULL);
|
||||
g_slist_free_full (results, (GDestroyNotify) free_result);
|
||||
|
||||
return sorted_results;
|
||||
}
|
||||
@ -463,6 +463,9 @@ shell_contact_system_initial_search (ShellContactSystem *self,
|
||||
g_object_unref (individual);
|
||||
}
|
||||
|
||||
g_object_unref (iter);
|
||||
g_slist_free_full (normalized_terms, (GDestroyNotify) g_free);
|
||||
|
||||
return sort_and_prepare_results (results);
|
||||
}
|
||||
|
||||
|
@ -230,6 +230,7 @@ auth_request_free (AuthRequest *request)
|
||||
g_free (request->message);
|
||||
g_free (request->icon_name);
|
||||
g_object_unref (request->details);
|
||||
g_free (request->cookie);
|
||||
g_list_foreach (request->identities, (GFunc) g_object_unref, NULL);
|
||||
g_list_free (request->identities);
|
||||
g_object_unref (request->simple);
|
||||
|
@ -341,3 +341,9 @@ shell_decline_dispatch_op (TpAddDispatchOperationContext *context,
|
||||
tp_add_dispatch_operation_context_fail (context, error);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
/* gjs doesn't cope with tp_proxy_get_invalidated() returning a GError */
|
||||
gboolean shell_is_channel_invalidated (TpChannel *channel)
|
||||
{
|
||||
return tp_proxy_get_invalidated (channel) != NULL;
|
||||
}
|
||||
|
@ -105,5 +105,7 @@ void shell_tp_client_grab_contact_list_changed (ShellTpClient *self,
|
||||
void shell_decline_dispatch_op (TpAddDispatchOperationContext *context,
|
||||
const gchar *message);
|
||||
|
||||
gboolean shell_is_channel_invalidated (TpChannel *channel);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* __SHELL_TP_CLIENT_H__ */
|
||||
|
@ -96,6 +96,7 @@ shell_util_get_file_display_for_common_files (GFile *file)
|
||||
* nautilus */
|
||||
return g_strdup (_("Home"));
|
||||
}
|
||||
g_object_unref (compare);
|
||||
|
||||
compare = g_file_new_for_path ("/");
|
||||
if (g_file_equal (file, compare))
|
||||
|
@ -357,7 +357,10 @@ update_focus_app (ShellWindowTracker *self)
|
||||
new_focus_app = new_focus_win ? shell_window_tracker_get_window_app (self, new_focus_win) : NULL;
|
||||
|
||||
if (new_focus_app)
|
||||
shell_app_update_window_actions (new_focus_app, new_focus_win);
|
||||
{
|
||||
shell_app_update_window_actions (new_focus_app, new_focus_win);
|
||||
shell_app_update_app_menu (new_focus_app, new_focus_win);
|
||||
}
|
||||
|
||||
set_focus_app (self, new_focus_app);
|
||||
}
|
||||
|
@ -933,6 +933,7 @@ load_gicon_with_colors (StTextureCache *cache,
|
||||
if (ensure_request (cache, key, policy, &request, texture))
|
||||
{
|
||||
/* If there's an outstanding request, we've just added ourselves to it */
|
||||
gtk_icon_info_free (info);
|
||||
g_free (key);
|
||||
}
|
||||
else
|
||||
|
@ -52,6 +52,7 @@ G_DEFINE_TYPE (StThemeContext, st_theme_context, G_TYPE_OBJECT)
|
||||
|
||||
static void on_icon_theme_changed (StTextureCache *cache,
|
||||
StThemeContext *context);
|
||||
static void st_theme_context_changed (StThemeContext *context);
|
||||
|
||||
static void
|
||||
st_theme_context_finalize (GObject *object)
|
||||
@ -61,6 +62,9 @@ st_theme_context_finalize (GObject *object)
|
||||
g_signal_handlers_disconnect_by_func (st_texture_cache_get_default (),
|
||||
(gpointer) on_icon_theme_changed,
|
||||
context);
|
||||
g_signal_handlers_disconnect_by_func (clutter_get_default_backend (),
|
||||
(gpointer) st_theme_context_changed,
|
||||
context);
|
||||
|
||||
if (context->root_node)
|
||||
g_object_unref (context->root_node);
|
||||
@ -97,6 +101,10 @@ st_theme_context_init (StThemeContext *context)
|
||||
"icon-theme-changed",
|
||||
G_CALLBACK (on_icon_theme_changed),
|
||||
context);
|
||||
g_signal_connect_swapped (clutter_get_default_backend (),
|
||||
"resolution-changed",
|
||||
G_CALLBACK (st_theme_context_changed),
|
||||
context);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -67,18 +67,6 @@ st_theme_node_dispose (GObject *gobject)
|
||||
{
|
||||
StThemeNode *node = ST_THEME_NODE (gobject);
|
||||
|
||||
if (node->context)
|
||||
{
|
||||
g_object_unref (node->context);
|
||||
node->context = NULL;
|
||||
}
|
||||
|
||||
if (node->theme)
|
||||
{
|
||||
g_object_unref (node->theme);
|
||||
node->theme = NULL;
|
||||
}
|
||||
|
||||
if (node->parent_node)
|
||||
{
|
||||
g_object_unref (node->parent_node);
|
||||
@ -97,6 +85,8 @@ st_theme_node_dispose (GObject *gobject)
|
||||
node->icon_colors = NULL;
|
||||
}
|
||||
|
||||
g_clear_object (&node->theme);
|
||||
|
||||
G_OBJECT_CLASS (st_theme_node_parent_class)->dispose (gobject);
|
||||
}
|
||||
|
||||
@ -194,7 +184,7 @@ st_theme_node_new (StThemeContext *context,
|
||||
|
||||
node = g_object_new (ST_TYPE_THEME_NODE, NULL);
|
||||
|
||||
node->context = g_object_ref (context);
|
||||
node->context = context;
|
||||
if (parent_node != NULL)
|
||||
node->parent_node = g_object_ref (parent_node);
|
||||
else
|
||||
@ -204,7 +194,10 @@ st_theme_node_new (StThemeContext *context,
|
||||
theme = parent_node->theme;
|
||||
|
||||
if (theme != NULL)
|
||||
node->theme = g_object_ref (theme);
|
||||
node->theme = theme;
|
||||
|
||||
if (node->theme != NULL)
|
||||
g_object_ref (node->theme);
|
||||
|
||||
node->element_type = element_type;
|
||||
node->element_id = g_strdup (element_id);
|
||||
|
@ -317,6 +317,7 @@ st_widget_finalize (GObject *gobject)
|
||||
g_free (priv->pseudo_class);
|
||||
g_object_unref (priv->local_state_set);
|
||||
g_free (priv->accessible_name);
|
||||
g_free (priv->inline_style);
|
||||
|
||||
G_OBJECT_CLASS (st_widget_parent_class)->finalize (gobject);
|
||||
}
|
||||
@ -762,18 +763,17 @@ st_widget_get_paint_volume (ClutterActor *self,
|
||||
static GList *
|
||||
st_widget_real_get_focus_chain (StWidget *widget)
|
||||
{
|
||||
GList *children;
|
||||
ClutterActorIter iter;
|
||||
ClutterActor *child;
|
||||
GList *focus_chain = NULL;
|
||||
|
||||
for (children = clutter_actor_get_children (CLUTTER_ACTOR (widget));
|
||||
children;
|
||||
children = children->next)
|
||||
clutter_actor_iter_init (&iter, CLUTTER_ACTOR (widget));
|
||||
while (clutter_actor_iter_next (&iter, &child))
|
||||
{
|
||||
ClutterActor *child = children->data;
|
||||
|
||||
if (CLUTTER_ACTOR_IS_VISIBLE (child))
|
||||
focus_chain = g_list_prepend (focus_chain, child);
|
||||
}
|
||||
|
||||
return g_list_reverse (focus_chain);
|
||||
}
|
||||
|
||||
@ -1011,7 +1011,7 @@ st_widget_class_init (StWidgetClass *klass)
|
||||
*/
|
||||
void
|
||||
st_widget_set_theme (StWidget *actor,
|
||||
StTheme *theme)
|
||||
StTheme *theme)
|
||||
{
|
||||
StWidgetPrivate *priv;
|
||||
|
||||
@ -1019,11 +1019,11 @@ st_widget_set_theme (StWidget *actor,
|
||||
|
||||
priv = actor->priv;
|
||||
|
||||
if (theme !=priv->theme)
|
||||
if (theme != priv->theme)
|
||||
{
|
||||
if (priv->theme)
|
||||
g_object_unref (priv->theme);
|
||||
priv->theme = g_object_ref (priv->theme);
|
||||
priv->theme = g_object_ref (theme);
|
||||
|
||||
st_widget_style_changed (actor);
|
||||
|
||||
@ -2503,6 +2503,8 @@ st_widget_accessible_dispose (GObject *gobject)
|
||||
g_object_unref (self->priv->current_label);
|
||||
self->priv->current_label = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (st_widget_accessible_parent_class)->dispose (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -425,6 +425,9 @@ main (int argc, char **argv)
|
||||
{
|
||||
StTheme *theme;
|
||||
StThemeContext *context;
|
||||
PangoFontDescription *font_desc;
|
||||
|
||||
gtk_init (&argc, &argv);
|
||||
|
||||
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
|
||||
return 1;
|
||||
@ -435,8 +438,10 @@ main (int argc, char **argv)
|
||||
stage = clutter_stage_new ();
|
||||
context = st_theme_context_get_for_stage (CLUTTER_STAGE (stage));
|
||||
st_theme_context_set_theme (context, theme);
|
||||
st_theme_context_set_font (context,
|
||||
pango_font_description_from_string ("sans-serif 12"));
|
||||
|
||||
font_desc = pango_font_description_from_string ("sans-serif 12");
|
||||
st_theme_context_set_font (context, font_desc);
|
||||
pango_font_description_free (font_desc);
|
||||
|
||||
root = st_theme_context_get_root_node (context);
|
||||
group1 = st_theme_node_new (context, root, NULL,
|
||||
@ -469,5 +474,17 @@ main (int argc, char **argv)
|
||||
test_pseudo_class ();
|
||||
test_inline_style ();
|
||||
|
||||
g_object_unref (cairo_texture);
|
||||
g_object_unref (group1);
|
||||
g_object_unref (group2);
|
||||
g_object_unref (group3);
|
||||
g_object_unref (text1);
|
||||
g_object_unref (text2);
|
||||
g_object_unref (text3);
|
||||
g_object_unref (text4);
|
||||
g_object_unref (theme);
|
||||
|
||||
clutter_actor_destroy (stage);
|
||||
|
||||
return fail ? 1 : 0;
|
||||
}
|
||||
|
@ -6,99 +6,97 @@ const St = imports.gi.St;
|
||||
|
||||
const UI = imports.testcommon.ui;
|
||||
|
||||
UI.init();
|
||||
let stage = Clutter.Stage.get_default();
|
||||
stage.user_resizable = true;
|
||||
stage.width = 1024;
|
||||
stage.height = 768;
|
||||
function test() {
|
||||
let stage = new Clutter.Stage({ user_resizable: true, width: 1024, height: 768 });
|
||||
UI.init(stage);
|
||||
|
||||
let vbox = new St.BoxLayout({ style: 'background: #ffee88;' });
|
||||
vbox.add_constraint(new Clutter.BindConstraint({ source: stage,
|
||||
coordinate: Clutter.BindCoordinate.SIZE }));
|
||||
stage.add_actor(vbox);
|
||||
let vbox = new St.BoxLayout({ style: 'background: #ffee88;' });
|
||||
vbox.add_constraint(new Clutter.BindConstraint({ source: stage,
|
||||
coordinate: Clutter.BindCoordinate.SIZE }));
|
||||
stage.add_actor(vbox);
|
||||
|
||||
let scroll = new St.ScrollView();
|
||||
vbox.add(scroll, { expand: true });
|
||||
let scroll = new St.ScrollView();
|
||||
vbox.add(scroll, { expand: true });
|
||||
|
||||
let vbox = new St.BoxLayout({ vertical: true,
|
||||
style: 'padding: 10px;'
|
||||
+ 'spacing: 20px;' });
|
||||
scroll.add_actor(vbox);
|
||||
let vbox = new St.BoxLayout({ vertical: true,
|
||||
style: 'padding: 10px;'
|
||||
+ 'spacing: 20px;' });
|
||||
scroll.add_actor(vbox);
|
||||
|
||||
let tbox = null;
|
||||
let tbox = null;
|
||||
|
||||
function addTestCase(image, size, backgroundSize, useCairo) {
|
||||
// Using a border in CSS forces cairo rendering.
|
||||
// To get a border using cogl, we paint a border using
|
||||
// paint signal hacks.
|
||||
function addTestCase(image, size, backgroundSize, useCairo) {
|
||||
// Using a border in CSS forces cairo rendering.
|
||||
// To get a border using cogl, we paint a border using
|
||||
// paint signal hacks.
|
||||
|
||||
let obin = new St.Bin();
|
||||
if (useCairo)
|
||||
obin.style = 'border: 3px solid green;';
|
||||
else
|
||||
obin.connect_after('paint', function(actor) {
|
||||
Cogl.set_source_color4f(0, 1, 0, 1);
|
||||
let obin = new St.Bin();
|
||||
if (useCairo)
|
||||
obin.style = 'border: 3px solid green;';
|
||||
else
|
||||
obin.connect_after('paint', function(actor) {
|
||||
Cogl.set_source_color4f(0, 1, 0, 1);
|
||||
|
||||
let geom = actor.get_allocation_geometry();
|
||||
let width = 3;
|
||||
let geom = actor.get_allocation_geometry();
|
||||
let width = 3;
|
||||
|
||||
// clockwise order
|
||||
Cogl.rectangle(0, 0, geom.width, width);
|
||||
Cogl.rectangle(geom.width - width, width,
|
||||
geom.width, geom.height);
|
||||
Cogl.rectangle(0, geom.height,
|
||||
geom.width - width, geom.height - width);
|
||||
Cogl.rectangle(0, geom.height - width,
|
||||
width, width);
|
||||
});
|
||||
tbox.add(obin);
|
||||
// clockwise order
|
||||
Cogl.rectangle(0, 0, geom.width, width);
|
||||
Cogl.rectangle(geom.width - width, width,
|
||||
geom.width, geom.height);
|
||||
Cogl.rectangle(0, geom.height,
|
||||
geom.width - width, geom.height - width);
|
||||
Cogl.rectangle(0, geom.height - width,
|
||||
width, width);
|
||||
});
|
||||
tbox.add(obin);
|
||||
|
||||
let [width, height] = size;
|
||||
let bin = new St.Bin({ style_class: 'background-image-' + image,
|
||||
width: width,
|
||||
height: height,
|
||||
style: 'border: 1px solid transparent;'
|
||||
+ 'background-size: ' + backgroundSize + ';',
|
||||
x_fill: true,
|
||||
y_fill: true
|
||||
});
|
||||
obin.set_child(bin);
|
||||
let [width, height] = size;
|
||||
let bin = new St.Bin({ style_class: 'background-image-' + image,
|
||||
width: width,
|
||||
height: height,
|
||||
style: 'border: 1px solid transparent;'
|
||||
+ 'background-size: ' + backgroundSize + ';',
|
||||
x_fill: true,
|
||||
y_fill: true
|
||||
});
|
||||
obin.set_child(bin);
|
||||
|
||||
bin.set_child(new St.Label({ text: backgroundSize + (useCairo ? ' (cairo)' : ' (cogl)'),
|
||||
style: 'font-size: 15px;'
|
||||
+ 'text-align: center;'
|
||||
}));
|
||||
bin.set_child(new St.Label({ text: backgroundSize + (useCairo ? ' (cairo)' : ' (cogl)'),
|
||||
style: 'font-size: 15px;'
|
||||
+ 'text-align: center;'
|
||||
}));
|
||||
}
|
||||
|
||||
function addTestLine(image, size, useCairo) {
|
||||
const backgroundSizes = ["auto", "contain", "cover", "200px 200px", "100px 100px", "100px 200px"];
|
||||
|
||||
let [width, height] = size;
|
||||
vbox.add(new St.Label({ text: image + '.svg / ' + width + '×' + height,
|
||||
style: 'font-size: 15px;'
|
||||
+ 'text-align: center;'
|
||||
}));
|
||||
|
||||
tbox = new St.BoxLayout({ style: 'spacing: 20px;' });
|
||||
vbox.add(tbox);
|
||||
|
||||
for each (let s in backgroundSizes)
|
||||
addTestCase(image, size, s, false);
|
||||
for each (let s in backgroundSizes)
|
||||
addTestCase(image, size, s, true);
|
||||
}
|
||||
|
||||
function addTestImage(image) {
|
||||
const containerSizes = [[100, 100], [200, 200], [250, 250], [100, 250], [250, 100]];
|
||||
|
||||
for each (let size in containerSizes)
|
||||
addTestLine(image, size);
|
||||
}
|
||||
|
||||
addTestImage ('200-200');
|
||||
addTestImage ('200-100');
|
||||
addTestImage ('100-200');
|
||||
|
||||
UI.main(stage);
|
||||
}
|
||||
|
||||
function addTestLine(image, size, useCairo) {
|
||||
const backgroundSizes = ["auto", "contain", "cover", "200px 200px", "100px 100px", "100px 200px"];
|
||||
|
||||
let [width, height] = size;
|
||||
vbox.add(new St.Label({ text: image + '.svg / ' + width + '×' + height,
|
||||
style: 'font-size: 15px;'
|
||||
+ 'text-align: center;'
|
||||
}));
|
||||
|
||||
tbox = new St.BoxLayout({ style: 'spacing: 20px;' });
|
||||
vbox.add(tbox);
|
||||
|
||||
for each (let s in backgroundSizes)
|
||||
addTestCase(image, size, s, false);
|
||||
for each (let s in backgroundSizes)
|
||||
addTestCase(image, size, s, true);
|
||||
}
|
||||
|
||||
function addTestImage(image) {
|
||||
const containerSizes = [[100, 100], [200, 200], [250, 250], [100, 250], [250, 100]];
|
||||
|
||||
for each (let size in containerSizes)
|
||||
addTestLine(image, size);
|
||||
}
|
||||
|
||||
addTestImage ('200-200');
|
||||
addTestImage ('200-100');
|
||||
addTestImage ('100-200');
|
||||
|
||||
stage.show();
|
||||
Clutter.main();
|
||||
stage.destroy();
|
||||
test();
|
||||
|
@ -5,59 +5,58 @@ const St = imports.gi.St;
|
||||
|
||||
const UI = imports.testcommon.ui;
|
||||
|
||||
UI.init();
|
||||
let stage = Clutter.Stage.get_default();
|
||||
stage.width = 640;
|
||||
stage.height = 480;
|
||||
function test() {
|
||||
let stage = new Clutter.Stage({ width: 640, height: 480 });
|
||||
UI.init(stage);
|
||||
|
||||
let vbox = new St.BoxLayout({ width: stage.width,
|
||||
height: stage.height,
|
||||
style: 'background: #ffee88;' });
|
||||
stage.add_actor(vbox);
|
||||
let vbox = new St.BoxLayout({ width: stage.width,
|
||||
height: stage.height,
|
||||
style: 'background: #ffee88;' });
|
||||
stage.add_actor(vbox);
|
||||
|
||||
let scroll = new St.ScrollView();
|
||||
vbox.add(scroll, { expand: true });
|
||||
let scroll = new St.ScrollView();
|
||||
vbox.add(scroll, { expand: true });
|
||||
|
||||
let box = new St.BoxLayout({ vertical: true,
|
||||
style: 'padding: 10px;'
|
||||
+ 'spacing: 20px;' });
|
||||
scroll.add_actor(box);
|
||||
let box = new St.BoxLayout({ vertical: true,
|
||||
style: 'padding: 10px;'
|
||||
+ 'spacing: 20px;' });
|
||||
scroll.add_actor(box);
|
||||
|
||||
function addTestCase(radii, useGradient) {
|
||||
let background;
|
||||
if (useGradient)
|
||||
background = 'background-gradient-direction: vertical;'
|
||||
+ 'background-gradient-start: white;'
|
||||
+ 'background-gradient-end: gray;';
|
||||
else
|
||||
background = 'background: white;';
|
||||
function addTestCase(radii, useGradient) {
|
||||
let background;
|
||||
if (useGradient)
|
||||
background = 'background-gradient-direction: vertical;'
|
||||
+ 'background-gradient-start: white;'
|
||||
+ 'background-gradient-end: gray;';
|
||||
else
|
||||
background = 'background: white;';
|
||||
|
||||
box.add(new St.Label({ text: "border-radius: " + radii + ";",
|
||||
style: 'border: 1px solid black; '
|
||||
+ 'border-radius: ' + radii + ';'
|
||||
+ 'padding: 5px;' + background }),
|
||||
{ x_fill: false });
|
||||
box.add(new St.Label({ text: "border-radius: " + radii + ";",
|
||||
style: 'border: 1px solid black; '
|
||||
+ 'border-radius: ' + radii + ';'
|
||||
+ 'padding: 5px;' + background }),
|
||||
{ x_fill: false });
|
||||
}
|
||||
|
||||
// uniform backgrounds
|
||||
addTestCase(" 0px 5px 10px 15px", false);
|
||||
addTestCase(" 5px 10px 15px 0px", false);
|
||||
addTestCase("10px 15px 0px 5px", false);
|
||||
addTestCase("15px 0px 5px 10px", false);
|
||||
|
||||
// gradient backgrounds
|
||||
addTestCase(" 0px 5px 10px 15px", true);
|
||||
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);
|
||||
|
||||
UI.main(stage);
|
||||
}
|
||||
|
||||
// uniform backgrounds
|
||||
addTestCase(" 0px 5px 10px 15px", false);
|
||||
addTestCase(" 5px 10px 15px 0px", false);
|
||||
addTestCase("10px 15px 0px 5px", false);
|
||||
addTestCase("15px 0px 5px 10px", false);
|
||||
|
||||
// gradient backgrounds
|
||||
addTestCase(" 0px 5px 10px 15px", true);
|
||||
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();
|
||||
test();
|
||||
|
@ -5,56 +5,55 @@ const St = imports.gi.St;
|
||||
|
||||
const UI = imports.testcommon.ui;
|
||||
|
||||
UI.init();
|
||||
let stage = Clutter.Stage.get_default();
|
||||
stage.width = 640;
|
||||
stage.height = 480;
|
||||
function test() {
|
||||
let stage = new Clutter.Stage({ width: 640, height: 480 });
|
||||
UI.init(stage);
|
||||
|
||||
let vbox = new St.BoxLayout({ width: stage.width,
|
||||
height: stage.height,
|
||||
style: 'padding: 10px; background: #ffee88;'
|
||||
});
|
||||
stage.add_actor(vbox);
|
||||
let vbox = new St.BoxLayout({ width: stage.width,
|
||||
height: stage.height,
|
||||
style: 'padding: 10px; background: #ffee88;'
|
||||
});
|
||||
stage.add_actor(vbox);
|
||||
|
||||
let scroll = new St.ScrollView();
|
||||
vbox.add(scroll, { expand: true });
|
||||
let scroll = new St.ScrollView();
|
||||
vbox.add(scroll, { expand: true });
|
||||
|
||||
let box = new St.BoxLayout({ vertical: true,
|
||||
style: 'spacing: 20px;' });
|
||||
scroll.add_actor(box);
|
||||
let box = new St.BoxLayout({ vertical: true,
|
||||
style: 'spacing: 20px;' });
|
||||
scroll.add_actor(box);
|
||||
|
||||
function addTestCase(borders, useGradient) {
|
||||
let background;
|
||||
if (useGradient)
|
||||
background = 'background-gradient-direction: vertical;'
|
||||
+ 'background-gradient-start: white;'
|
||||
+ 'background-gradient-end: gray;';
|
||||
else
|
||||
background = 'background: white;';
|
||||
function addTestCase(borders, useGradient) {
|
||||
let background;
|
||||
if (useGradient)
|
||||
background = 'background-gradient-direction: vertical;'
|
||||
+ 'background-gradient-start: white;'
|
||||
+ 'background-gradient-end: gray;';
|
||||
else
|
||||
background = 'background: white;';
|
||||
|
||||
let border_style = "border-top: " + borders[St.Side.TOP] + " solid black;\n" +
|
||||
"border-right: " + borders[St.Side.RIGHT] + " solid black;\n" +
|
||||
"border-bottom: " + borders[St.Side.BOTTOM] + " solid black;\n" +
|
||||
"border-left: " + borders[St.Side.LEFT] + " solid black;";
|
||||
box.add(new St.Label({ text: border_style,
|
||||
style: border_style
|
||||
+ 'border-radius: 0px 5px 15px 25px;'
|
||||
+ 'padding: 5px;' + background }),
|
||||
{ x_fill: false });
|
||||
let border_style = "border-top: " + borders[St.Side.TOP] + " solid black;\n" +
|
||||
"border-right: " + borders[St.Side.RIGHT] + " solid black;\n" +
|
||||
"border-bottom: " + borders[St.Side.BOTTOM] + " solid black;\n" +
|
||||
"border-left: " + borders[St.Side.LEFT] + " solid black;";
|
||||
box.add(new St.Label({ text: border_style,
|
||||
style: border_style
|
||||
+ 'border-radius: 0px 5px 15px 25px;'
|
||||
+ 'padding: 5px;' + background }),
|
||||
{ x_fill: false });
|
||||
}
|
||||
|
||||
// uniform backgrounds
|
||||
addTestCase([" 0px", " 5px", "10px", "15px"], false);
|
||||
addTestCase([" 5px", "10px", "15px", " 0px"], false);
|
||||
addTestCase(["10px", "15px", " 0px", " 5px"], false);
|
||||
addTestCase(["15px", " 0px", " 5px", "10px"], false);
|
||||
|
||||
// gradient backgrounds
|
||||
addTestCase([" 0px", " 5px", "10px", "15px"], true);
|
||||
addTestCase([" 5px", "10px", "15px", " 0px"], true);
|
||||
addTestCase(["10px", "15px", " 0px", " 5px"], true);
|
||||
addTestCase(["15px", " 0px", " 5px", "10px"], true);
|
||||
|
||||
UI.main(stage);
|
||||
}
|
||||
|
||||
// uniform backgrounds
|
||||
addTestCase([" 0px", " 5px", "10px", "15px"], false);
|
||||
addTestCase([" 5px", "10px", "15px", " 0px"], false);
|
||||
addTestCase(["10px", "15px", " 0px", " 5px"], false);
|
||||
addTestCase(["15px", " 0px", " 5px", "10px"], false);
|
||||
|
||||
// gradient backgrounds
|
||||
addTestCase([" 0px", " 5px", "10px", "15px"], true);
|
||||
addTestCase([" 5px", "10px", "15px", " 0px"], true);
|
||||
addTestCase(["10px", "15px", " 0px", " 5px"], true);
|
||||
addTestCase(["15px", " 0px", " 5px", "10px"], true);
|
||||
|
||||
stage.show();
|
||||
Clutter.main();
|
||||
stage.destroy();
|
||||
test();
|
||||
|
@ -5,131 +5,131 @@ const St = imports.gi.St;
|
||||
|
||||
const UI = imports.testcommon.ui;
|
||||
|
||||
UI.init();
|
||||
let stage = Clutter.Stage.get_default();
|
||||
stage.width = 640;
|
||||
stage.height = 480;
|
||||
function test() {
|
||||
let stage = new Clutter.Stage({ width: 640, height: 480 });
|
||||
UI.init(stage);
|
||||
|
||||
let vbox = new St.BoxLayout({ width: stage.width,
|
||||
height: stage.height,
|
||||
style: 'background: #ffee88;' });
|
||||
stage.add_actor(vbox);
|
||||
let vbox = new St.BoxLayout({ width: stage.width,
|
||||
height: stage.height,
|
||||
style: 'background: #ffee88;' });
|
||||
stage.add_actor(vbox);
|
||||
|
||||
let scroll = new St.ScrollView();
|
||||
vbox.add(scroll, { expand: true });
|
||||
let scroll = new St.ScrollView();
|
||||
vbox.add(scroll, { expand: true });
|
||||
|
||||
let box = new St.BoxLayout({ vertical: true,
|
||||
style: 'padding: 10px;'
|
||||
+ 'spacing: 20px;' });
|
||||
scroll.add_actor(box);
|
||||
let box = new St.BoxLayout({ vertical: true,
|
||||
style: 'padding: 10px;'
|
||||
+ 'spacing: 20px;' });
|
||||
scroll.add_actor(box);
|
||||
|
||||
box.add(new St.Label({ text: "Hello World",
|
||||
style: 'border: 1px solid black; '
|
||||
+ 'padding: 5px;' }));
|
||||
box.add(new St.Label({ text: "Hello World",
|
||||
style: 'border: 1px solid black; '
|
||||
+ 'padding: 5px;' }));
|
||||
|
||||
box.add(new St.Label({ text: "Hello Round World",
|
||||
style: 'border: 3px solid green; '
|
||||
+ 'border-radius: 8px; '
|
||||
+ 'padding: 5px;' }));
|
||||
box.add(new St.Label({ text: "Hello Round World",
|
||||
style: 'border: 3px solid green; '
|
||||
+ 'border-radius: 8px; '
|
||||
+ 'padding: 5px;' }));
|
||||
|
||||
box.add(new St.Label({ text: "Hello Background",
|
||||
style: 'border: 3px solid green; '
|
||||
+ 'border-radius: 8px; '
|
||||
+ 'background: white; '
|
||||
+ 'padding: 5px;' }));
|
||||
box.add(new St.Label({ text: "Hello Background",
|
||||
style: 'border: 3px solid green; '
|
||||
+ 'border-radius: 8px; '
|
||||
+ 'background: white; '
|
||||
+ 'padding: 5px;' }));
|
||||
|
||||
box.add(new St.Label({ text: "Hello Translucent Black Border",
|
||||
style: 'border: 3px solid rgba(0, 0, 0, 0.4); '
|
||||
+ 'background: white; ' }));
|
||||
box.add(new St.Label({ text: "Hello Translucent Black Border",
|
||||
style: 'border: 3px solid rgba(0, 0, 0, 0.4); '
|
||||
+ 'background: white; ' }));
|
||||
|
||||
box.add(new St.Label({ text: "Hello Translucent Background",
|
||||
style: 'background: rgba(255, 255, 255, 0.3);' }));
|
||||
box.add(new St.Label({ text: "Hello Translucent Background",
|
||||
style: 'background: rgba(255, 255, 255, 0.3);' }));
|
||||
|
||||
box.add(new St.Label({ text: "Border, Padding, Content: 20px" }));
|
||||
box.add(new St.Label({ text: "Border, Padding, Content: 20px" }));
|
||||
|
||||
let b1 = new St.BoxLayout({ vertical: true,
|
||||
style: 'border: 20px solid black; '
|
||||
+ 'background: white; '
|
||||
+ 'padding: 20px;' });
|
||||
box.add(b1);
|
||||
let b1 = new St.BoxLayout({ vertical: true,
|
||||
style: 'border: 20px solid black; '
|
||||
+ 'background: white; '
|
||||
+ 'padding: 20px;' });
|
||||
box.add(b1);
|
||||
|
||||
b1.add(new St.BoxLayout({ width: 20, height: 20,
|
||||
style: 'background: black' }));
|
||||
b1.add(new St.BoxLayout({ width: 20, height: 20,
|
||||
style: 'background: black' }));
|
||||
|
||||
box.add(new St.Label({ text: "Translucent big blue border, with rounding",
|
||||
style: 'border: 20px solid rgba(0, 0, 255, 0.2); '
|
||||
+ 'border-radius: 10px; '
|
||||
+ 'background: white; '
|
||||
+ 'padding: 10px;' }));
|
||||
box.add(new St.Label({ text: "Translucent big blue border, with rounding",
|
||||
style: 'border: 20px solid rgba(0, 0, 255, 0.2); '
|
||||
+ 'border-radius: 10px; '
|
||||
+ 'background: white; '
|
||||
+ 'padding: 10px;' }));
|
||||
|
||||
box.add(new St.Label({ text: "Transparent border",
|
||||
style: 'border: 20px solid transparent; '
|
||||
+ 'background: white; '
|
||||
+ 'padding: 10px;' }));
|
||||
box.add(new St.Label({ text: "Transparent border",
|
||||
style: 'border: 20px solid transparent; '
|
||||
+ 'background: white; '
|
||||
+ 'padding: 10px;' }));
|
||||
|
||||
box.add(new St.Label({ text: "Border Image",
|
||||
style_class: "border-image",
|
||||
style: "padding: 10px;" }));
|
||||
box.add(new St.Label({ text: "Border Image",
|
||||
style_class: "border-image",
|
||||
style: "padding: 10px;" }));
|
||||
|
||||
box.add(new St.Label({ text: "Border Image with Gradient",
|
||||
style_class: 'border-image-with-background-gradient',
|
||||
style: "padding: 10px;"
|
||||
+ 'background-gradient-direction: vertical;' }));
|
||||
box.add(new St.Label({ text: "Border Image with Gradient",
|
||||
style_class: 'border-image-with-background-gradient',
|
||||
style: "padding: 10px;"
|
||||
+ 'background-gradient-direction: vertical;' }));
|
||||
|
||||
box.add(new St.Label({ text: "Rounded, framed, shadowed gradients" }));
|
||||
box.add(new St.Label({ text: "Rounded, framed, shadowed gradients" }));
|
||||
|
||||
let framedGradients = new St.BoxLayout({ vertical: false,
|
||||
style: 'padding: 10px; spacing: 12px;' });
|
||||
box.add(framedGradients);
|
||||
let framedGradients = new St.BoxLayout({ vertical: false,
|
||||
style: 'padding: 10px; spacing: 12px;' });
|
||||
box.add(framedGradients);
|
||||
|
||||
function addGradientCase(direction, borderWidth, borderRadius, extra) {
|
||||
let gradientBox = new St.BoxLayout({ style_class: 'background-gradient',
|
||||
style: 'border: ' + borderWidth + 'px solid #8b0000;'
|
||||
+ 'border-radius: ' + borderRadius + 'px;'
|
||||
+ 'background-gradient-direction: ' + direction + ';'
|
||||
+ 'width: 32px;'
|
||||
+ 'height: 32px;'
|
||||
+ extra });
|
||||
framedGradients.add(gradientBox, { x_fill: false, y_fill: false } );
|
||||
}
|
||||
|
||||
addGradientCase ('horizontal', 0, 5, 'box-shadow: 0px 0px 0px 0px rgba(0,0,0,0.5);');
|
||||
addGradientCase ('horizontal', 2, 5, 'box-shadow: 0px 2px 0px 0px rgba(0,255,0,0.5);');
|
||||
addGradientCase ('horizontal', 5, 2, 'box-shadow: 2px 0px 0px 0px rgba(0,0,255,0.5);');
|
||||
addGradientCase ('horizontal', 5, 20, 'box-shadow: 0px 0px 4px 0px rgba(255,0,0,0.5);');
|
||||
addGradientCase ('vertical', 0, 5, 'box-shadow: 0px 0px 0px 4px rgba(0,0,0,0.5);');
|
||||
addGradientCase ('vertical', 2, 5, 'box-shadow: 0px 0px 4px 4px rgba(0,0,0,0.5);');
|
||||
addGradientCase ('vertical', 5, 2, 'box-shadow: -2px -2px 6px 0px rgba(0,0,0,0.5);');
|
||||
addGradientCase ('vertical', 5, 20, 'box-shadow: -2px -2px 0px 6px rgba(0,0,0,0.5);');
|
||||
|
||||
box.add(new St.Label({ text: "Rounded, framed, shadowed images" }));
|
||||
|
||||
let framedImages = new St.BoxLayout({ vertical: false,
|
||||
style: 'padding: 10px; spacing: 6px;' });
|
||||
box.add(framedImages);
|
||||
|
||||
function addBackgroundImageCase(borderWidth, borderRadius, width, height, extra) {
|
||||
let imageBox = new St.BoxLayout({ style_class: 'background-image',
|
||||
style: 'border: ' + borderWidth + 'px solid #8b8b8b;'
|
||||
function addGradientCase(direction, borderWidth, borderRadius, extra) {
|
||||
let gradientBox = new St.BoxLayout({ style_class: 'background-gradient',
|
||||
style: 'border: ' + borderWidth + 'px solid #8b0000;'
|
||||
>>>>>>> 2aff593... tests: Run each test in a function
|
||||
+ 'border-radius: ' + borderRadius + 'px;'
|
||||
+ 'width: ' + width + 'px;'
|
||||
+ 'height: ' + height + 'px;'
|
||||
+ 'background-gradient-direction: ' + direction + ';'
|
||||
+ 'width: 32px;'
|
||||
+ 'height: 32px;'
|
||||
+ extra });
|
||||
framedImages.add(imageBox, { x_fill: false, y_fill: false } );
|
||||
framedGradients.add(gradientBox, { x_fill: false, y_fill: false } );
|
||||
}
|
||||
|
||||
addGradientCase ('horizontal', 0, 5, 'box-shadow: 0px 0px 0px 0px rgba(0,0,0,0.5);');
|
||||
addGradientCase ('horizontal', 2, 5, 'box-shadow: 0px 2px 0px 0px rgba(0,255,0,0.5);');
|
||||
addGradientCase ('horizontal', 5, 2, 'box-shadow: 2px 0px 0px 0px rgba(0,0,255,0.5);');
|
||||
addGradientCase ('horizontal', 5, 20, 'box-shadow: 0px 0px 4px 0px rgba(255,0,0,0.5);');
|
||||
addGradientCase ('vertical', 0, 5, 'box-shadow: 0px 0px 0px 4px rgba(0,0,0,0.5);');
|
||||
addGradientCase ('vertical', 2, 5, 'box-shadow: 0px 0px 4px 4px rgba(0,0,0,0.5);');
|
||||
addGradientCase ('vertical', 5, 2, 'box-shadow: -2px -2px 6px 0px rgba(0,0,0,0.5);');
|
||||
addGradientCase ('vertical', 5, 20, 'box-shadow: -2px -2px 0px 6px rgba(0,0,0,0.5);');
|
||||
|
||||
box.add(new St.Label({ text: "Rounded, framed, shadowed images" }));
|
||||
|
||||
let framedImages = new St.BoxLayout({ vertical: false,
|
||||
style: 'padding: 10px; spacing: 6px;' });
|
||||
box.add(framedImages);
|
||||
|
||||
function addBackgroundImageCase(borderWidth, borderRadius, width, height, extra) {
|
||||
let imageBox = new St.BoxLayout({ style_class: 'background-image',
|
||||
style: 'border: ' + borderWidth + 'px solid #8b8b8b;'
|
||||
+ 'border-radius: ' + borderRadius + 'px;'
|
||||
+ 'width: ' + width + 'px;'
|
||||
+ 'height: ' + height + 'px;'
|
||||
+ extra });
|
||||
framedImages.add(imageBox, { x_fill: false, y_fill: false } );
|
||||
}
|
||||
|
||||
addBackgroundImageCase (0, 0, 32, 32, 'background-position: 2px 5px');
|
||||
addBackgroundImageCase (0, 0, 16, 16, '-st-background-image-shadow: 1px 1px 4px 0px rgba(0,0,0,0.5); background-color: rgba(0,0,0,0)');
|
||||
addBackgroundImageCase (0, 5, 32, 32, '-st-background-image-shadow: 0px 0px 0px 0px rgba(0,0,0,0.5);');
|
||||
addBackgroundImageCase (2, 5, 32, 32, '-st-background-image-shadow: 0px 2px 0px 0px rgba(0,255,0,0.5);');
|
||||
addBackgroundImageCase (5, 2, 32, 32, '-st-background-image-shadow: 2px 0px 0px 0px rgba(0,0,255,0.5);');
|
||||
addBackgroundImageCase (5, 20, 32, 32, '-st-background-image-shadow: 0px 0px 4px 0px rgba(255,0,0,0.5);');
|
||||
addBackgroundImageCase (0, 5, 48, 48, '-st-background-image-shadow: 0px 0px 0px 4px rgba(0,0,0,0.5);');
|
||||
addBackgroundImageCase (5, 5, 48, 48, '-st-background-image-shadow: 0px 0px 4px 4px rgba(0,0,0,0.5);');
|
||||
addBackgroundImageCase (0, 5, 64, 64, '-st-background-image-shadow: -2px -2px 6px 0px rgba(0,0,0,0.5);');
|
||||
addBackgroundImageCase (5, 5, 64, 64, '-st-background-image-shadow: -2px -2px 0px 6px rgba(0,0,0,0.5);');
|
||||
addBackgroundImageCase (0, 5, 32, 32, 'background-position: 2px 5px');
|
||||
|
||||
UI.main(stage);
|
||||
}
|
||||
|
||||
addBackgroundImageCase (0, 0, 32, 32, 'background-position: 2px 5px');
|
||||
addBackgroundImageCase (0, 0, 16, 16, '-st-background-image-shadow: 1px 1px 4px 0px rgba(0,0,0,0.5); background-color: rgba(0,0,0,0)');
|
||||
addBackgroundImageCase (0, 5, 32, 32, '-st-background-image-shadow: 0px 0px 0px 0px rgba(0,0,0,0.5);');
|
||||
addBackgroundImageCase (2, 5, 32, 32, '-st-background-image-shadow: 0px 2px 0px 0px rgba(0,255,0,0.5);');
|
||||
addBackgroundImageCase (5, 2, 32, 32, '-st-background-image-shadow: 2px 0px 0px 0px rgba(0,0,255,0.5);');
|
||||
addBackgroundImageCase (5, 20, 32, 32, '-st-background-image-shadow: 0px 0px 4px 0px rgba(255,0,0,0.5);');
|
||||
addBackgroundImageCase (0, 5, 48, 48, '-st-background-image-shadow: 0px 0px 0px 4px rgba(0,0,0,0.5);');
|
||||
addBackgroundImageCase (5, 5, 48, 48, '-st-background-image-shadow: 0px 0px 4px 4px rgba(0,0,0,0.5);');
|
||||
addBackgroundImageCase (0, 5, 64, 64, '-st-background-image-shadow: -2px -2px 6px 0px rgba(0,0,0,0.5);');
|
||||
addBackgroundImageCase (5, 5, 64, 64, '-st-background-image-shadow: -2px -2px 0px 6px rgba(0,0,0,0.5);');
|
||||
addBackgroundImageCase (0, 5, 32, 32, 'background-position: 2px 5px');
|
||||
|
||||
stage.show();
|
||||
Clutter.main();
|
||||
stage.destroy();
|
||||
test();
|
||||
|
@ -5,88 +5,87 @@ const St = imports.gi.St;
|
||||
|
||||
const UI = imports.testcommon.ui;
|
||||
|
||||
UI.init();
|
||||
let stage = Clutter.Stage.get_default();
|
||||
function test() {
|
||||
let stage = new Clutter.Stage();
|
||||
UI.init(stage);
|
||||
|
||||
let vbox = new St.BoxLayout({ vertical: true,
|
||||
width: stage.width,
|
||||
height: stage.height,
|
||||
style: 'padding: 10px;'
|
||||
+ 'spacing: 10px;' });
|
||||
stage.add_actor(vbox);
|
||||
let vbox = new St.BoxLayout({ vertical: true,
|
||||
width: stage.width,
|
||||
height: stage.height,
|
||||
style: 'padding: 10px;'
|
||||
+ 'spacing: 10px;' });
|
||||
stage.add_actor(vbox);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
let colored_boxes = new St.BoxLayout({ vertical: true,
|
||||
width: 200,
|
||||
height: 200,
|
||||
style: 'border: 2px solid black;' });
|
||||
vbox.add(colored_boxes, { x_fill: false,
|
||||
x_align: St.Align.MIDDLE });
|
||||
let colored_boxes = new St.BoxLayout({ vertical: true,
|
||||
width: 200,
|
||||
height: 200,
|
||||
style: 'border: 2px solid black;' });
|
||||
vbox.add(colored_boxes, { x_fill: false,
|
||||
x_align: St.Align.MIDDLE });
|
||||
|
||||
let b2 = new St.BoxLayout({ style: 'border: 2px solid #666666' });
|
||||
colored_boxes.add(b2, { expand: true });
|
||||
let b2 = new St.BoxLayout({ style: 'border: 2px solid #666666' });
|
||||
colored_boxes.add(b2, { expand: true });
|
||||
|
||||
b2.add(new St.Label({ text: "Expand",
|
||||
style: 'border: 1px solid #aaaaaa; '
|
||||
+ 'background: #ffeecc' }),
|
||||
{ expand: true });
|
||||
b2.add(new St.Label({ text: "Expand\nNo Fill",
|
||||
style: 'border: 1px solid #aaaaaa; '
|
||||
+ 'background: #ccffaa' }),
|
||||
{ expand: true,
|
||||
x_fill: false,
|
||||
x_align: St.Align.MIDDLE,
|
||||
y_fill: false,
|
||||
y_align: St.Align.MIDDLE });
|
||||
b2.add(new St.Label({ text: "Expand",
|
||||
style: 'border: 1px solid #aaaaaa; '
|
||||
+ 'background: #ffeecc' }),
|
||||
{ expand: true });
|
||||
b2.add(new St.Label({ text: "Expand\nNo Fill",
|
||||
style: 'border: 1px solid #aaaaaa; '
|
||||
+ 'background: #ccffaa' }),
|
||||
{ expand: true,
|
||||
x_fill: false,
|
||||
x_align: St.Align.MIDDLE,
|
||||
y_fill: false,
|
||||
y_align: St.Align.MIDDLE });
|
||||
|
||||
colored_boxes.add(new St.Label({ text: "Default",
|
||||
style: 'border: 1px solid #aaaaaa; '
|
||||
+ 'background: #cceeff' }));
|
||||
colored_boxes.add(new St.Label({ text: "Default",
|
||||
style: 'border: 1px solid #aaaaaa; '
|
||||
+ 'background: #cceeff' }));
|
||||
|
||||
b2.add(new St.Label({ x: 50,
|
||||
y: 50,
|
||||
text: "Fixed",
|
||||
style: 'border: 1px solid #aaaaaa;'
|
||||
+ 'background: #ffffcc' }));
|
||||
b2.add(new St.Label({ x: 50,
|
||||
y: 50,
|
||||
text: "Fixed",
|
||||
style: 'border: 1px solid #aaaaaa;'
|
||||
+ 'background: #ffffcc' }));
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function createCollapsableBox(width) {
|
||||
let b = new St.BoxLayout({ width: width,
|
||||
style: 'border: 1px solid black;'
|
||||
+ 'font: 13px Sans;' });
|
||||
b.add(new St.Label({ text: "Very Very Very Long",
|
||||
style: 'background: #ffaacc;'
|
||||
+ 'padding: 5px; '
|
||||
+ 'border: 1px solid #666666;' }),
|
||||
{ expand: true });
|
||||
b.add(new St.Label({ text: "Very Very Long",
|
||||
style: 'background: #ffeecc; '
|
||||
+ 'padding: 5px; '
|
||||
+ 'border: 1px solid #666666;' }),
|
||||
{ expand: true });
|
||||
b.add(new St.Label({ text: "Very Long",
|
||||
style: 'background: #ccffaa; '
|
||||
+ 'padding: 5px; '
|
||||
+ 'border: 1px solid #666666;' }),
|
||||
{ expand: true });
|
||||
b.add(new St.Label({ text: "Short",
|
||||
style: 'background: #cceeff; '
|
||||
+ 'padding: 5px; '
|
||||
+ 'border: 1px solid #666666;' }),
|
||||
{ expand: true });
|
||||
function createCollapsableBox(width) {
|
||||
let b = new St.BoxLayout({ width: width,
|
||||
style: 'border: 1px solid black;'
|
||||
+ 'font: 13px Sans;' });
|
||||
b.add(new St.Label({ text: "Very Very Very Long",
|
||||
style: 'background: #ffaacc;'
|
||||
+ 'padding: 5px; '
|
||||
+ 'border: 1px solid #666666;' }),
|
||||
{ expand: true });
|
||||
b.add(new St.Label({ text: "Very Very Long",
|
||||
style: 'background: #ffeecc; '
|
||||
+ 'padding: 5px; '
|
||||
+ 'border: 1px solid #666666;' }),
|
||||
{ expand: true });
|
||||
b.add(new St.Label({ text: "Very Long",
|
||||
style: 'background: #ccffaa; '
|
||||
+ 'padding: 5px; '
|
||||
+ 'border: 1px solid #666666;' }),
|
||||
{ expand: true });
|
||||
b.add(new St.Label({ text: "Short",
|
||||
style: 'background: #cceeff; '
|
||||
+ 'padding: 5px; '
|
||||
+ 'border: 1px solid #666666;' }),
|
||||
{ expand: true });
|
||||
|
||||
return b;
|
||||
return b;
|
||||
}
|
||||
|
||||
for (let width = 200; width <= 500; width += 60 ) {
|
||||
vbox.add(createCollapsableBox (width),
|
||||
{ x_fill: false,
|
||||
x_align: St.Align.MIDDLE });
|
||||
}
|
||||
|
||||
UI.main(stage);
|
||||
}
|
||||
|
||||
for (let width = 200; width <= 500; width += 60 ) {
|
||||
vbox.add(createCollapsableBox (width),
|
||||
{ x_fill: false,
|
||||
x_align: St.Align.MIDDLE });
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
stage.show();
|
||||
Clutter.main();
|
||||
|
@ -5,54 +5,53 @@ const St = imports.gi.St;
|
||||
|
||||
const UI = imports.testcommon.ui;
|
||||
|
||||
UI.init();
|
||||
let stage = Clutter.Stage.get_default();
|
||||
stage.width = 640;
|
||||
stage.height = 480;
|
||||
function test() {
|
||||
let stage = new Clutter.Stage({ width: 640, height: 480 });
|
||||
UI.init(stage);
|
||||
|
||||
let vbox = new St.BoxLayout({ width: stage.width,
|
||||
height: stage.height,
|
||||
style: 'background: #ffee88;' });
|
||||
stage.add_actor(vbox);
|
||||
let vbox = new St.BoxLayout({ width: stage.width,
|
||||
height: stage.height,
|
||||
style: 'background: #ffee88;' });
|
||||
stage.add_actor(vbox);
|
||||
|
||||
let scroll = new St.ScrollView();
|
||||
vbox.add(scroll, { expand: true });
|
||||
let scroll = new St.ScrollView();
|
||||
vbox.add(scroll, { expand: true });
|
||||
|
||||
let box = new St.BoxLayout({ vertical: true,
|
||||
style: 'padding: 10px;'
|
||||
+ 'spacing: 20px;' });
|
||||
scroll.add_actor(box);
|
||||
let box = new St.BoxLayout({ vertical: true,
|
||||
style: 'padding: 10px;'
|
||||
+ 'spacing: 20px;' });
|
||||
scroll.add_actor(box);
|
||||
|
||||
|
||||
function addTestCase(inset, offsetX, offsetY, blur, spread) {
|
||||
let shadowStyle = 'box-shadow: ' + (inset ? 'inset ' : '') +
|
||||
offsetX + 'px ' + offsetY + 'px ' + blur + 'px ' +
|
||||
(spread > 0 ? (' ' + spread + 'px ') : '') +
|
||||
'rgba(0,0,0,0.5);';
|
||||
let label = new St.Label({ style: 'border: 4px solid black;' +
|
||||
'border-radius: 5px;' +
|
||||
'background-color: white; ' +
|
||||
'padding: 5px;' +
|
||||
shadowStyle,
|
||||
text: shadowStyle });
|
||||
box.add(label, { x_fill: false, y_fill: false } );
|
||||
function addTestCase(inset, offsetX, offsetY, blur, spread) {
|
||||
let shadowStyle = 'box-shadow: ' + (inset ? 'inset ' : '') +
|
||||
offsetX + 'px ' + offsetY + 'px ' + blur + 'px ' +
|
||||
(spread > 0 ? (' ' + spread + 'px ') : '') +
|
||||
'rgba(0,0,0,0.5);';
|
||||
let label = new St.Label({ style: 'border: 4px solid black;' +
|
||||
'border-radius: 5px;' +
|
||||
'background-color: white; ' +
|
||||
'padding: 5px;' +
|
||||
shadowStyle,
|
||||
text: shadowStyle });
|
||||
box.add(label, { x_fill: false, y_fill: false } );
|
||||
}
|
||||
|
||||
addTestCase (false, 3, 4, 0, 0);
|
||||
addTestCase (false, 3, 4, 0, 4);
|
||||
addTestCase (false, 3, 4, 4, 0);
|
||||
addTestCase (false, 3, 4, 4, 4);
|
||||
addTestCase (false, -3, -4, 4, 0);
|
||||
addTestCase (false, 0, 0, 0, 4);
|
||||
addTestCase (false, 0, 0, 4, 0);
|
||||
addTestCase (true, 3, 4, 0, 0);
|
||||
addTestCase (true, 3, 4, 0, 4);
|
||||
addTestCase (true, 3, 4, 4, 0);
|
||||
addTestCase (true, 3, 4, 4, 4);
|
||||
addTestCase (true, -3, -4, 4, 0);
|
||||
addTestCase (true, 0, 0, 0, 4);
|
||||
addTestCase (true, 0, 0, 4, 0);
|
||||
|
||||
UI.main(stage);
|
||||
}
|
||||
|
||||
addTestCase (false, 3, 4, 0, 0);
|
||||
addTestCase (false, 3, 4, 0, 4);
|
||||
addTestCase (false, 3, 4, 4, 0);
|
||||
addTestCase (false, 3, 4, 4, 4);
|
||||
addTestCase (false, -3, -4, 4, 0);
|
||||
addTestCase (false, 0, 0, 0, 4);
|
||||
addTestCase (false, 0, 0, 4, 0);
|
||||
addTestCase (true, 3, 4, 0, 0);
|
||||
addTestCase (true, 3, 4, 0, 4);
|
||||
addTestCase (true, 3, 4, 4, 0);
|
||||
addTestCase (true, 3, 4, 4, 4);
|
||||
addTestCase (true, -3, -4, 4, 0);
|
||||
addTestCase (true, 0, 0, 0, 4);
|
||||
addTestCase (true, 0, 0, 4, 0);
|
||||
|
||||
stage.show();
|
||||
Clutter.main();
|
||||
stage.destroy();
|
||||
test();
|
||||
|
@ -7,23 +7,22 @@ const St = imports.gi.St;
|
||||
const Calendar = imports.ui.calendar;
|
||||
const UI = imports.testcommon.ui;
|
||||
|
||||
UI.init();
|
||||
let stage = Clutter.Stage.get_default();
|
||||
stage.width = stage.height = 400;
|
||||
stage.show();
|
||||
function test() {
|
||||
let stage = new Clutter.Stage({ width: 400, height: 400 });
|
||||
UI.init(stage);
|
||||
|
||||
let vbox = new St.BoxLayout({ vertical: true,
|
||||
width: stage.width,
|
||||
height: stage.height,
|
||||
style: 'padding: 10px; spacing: 10px; font: 15px sans-serif;' });
|
||||
stage.add_actor(vbox);
|
||||
let vbox = new St.BoxLayout({ vertical: true,
|
||||
width: stage.width,
|
||||
height: stage.height,
|
||||
style: 'padding: 10px; spacing: 10px; font: 15px sans-serif;' });
|
||||
stage.add_actor(vbox);
|
||||
|
||||
let calendar = new Calendar.Calendar();
|
||||
vbox.add(calendar.actor,
|
||||
{ expand: true,
|
||||
x_fill: false, x_align: St.Align.MIDDLE,
|
||||
y_fill: false, y_align: St.Align.START });
|
||||
let calendar = new Calendar.Calendar();
|
||||
vbox.add(calendar.actor,
|
||||
{ expand: true,
|
||||
x_fill: false, x_align: St.Align.MIDDLE,
|
||||
y_fill: false, y_align: St.Align.START });
|
||||
|
||||
stage.show();
|
||||
Clutter.main();
|
||||
stage.destroy();
|
||||
UI.main(stage);
|
||||
}
|
||||
test();
|
||||
|
@ -5,35 +5,37 @@ const St = imports.gi.St;
|
||||
|
||||
const UI = imports.testcommon.ui;
|
||||
|
||||
UI.init();
|
||||
let stage = Clutter.Stage.get_default();
|
||||
function test() {
|
||||
let stage = new Clutter.Stage();
|
||||
UI.init(stage);
|
||||
|
||||
let b = new St.BoxLayout({ vertical: true,
|
||||
width: stage.width,
|
||||
height: stage.height });
|
||||
stage.add_actor(b);
|
||||
let b = new St.BoxLayout({ vertical: true,
|
||||
width: stage.width,
|
||||
height: stage.height });
|
||||
stage.add_actor(b);
|
||||
|
||||
let t;
|
||||
let t;
|
||||
|
||||
t = new St.Label({ "text": "Bold", style_class: "bold" });
|
||||
b.add(t);
|
||||
t = new St.Label({ "text": "Monospace", style_class: "monospace" });
|
||||
b.add(t);
|
||||
t = new St.Label({ "text": "Italic", style_class: "italic" });
|
||||
b.add(t);
|
||||
t = new St.Label({ "text": "Bold Italic", style_class: "bold italic" });
|
||||
b.add(t);
|
||||
t = new St.Label({ "text": "Big Italic", style_class: "big italic" });
|
||||
b.add(t);
|
||||
t = new St.Label({ "text": "Big Bold", style_class: "big bold" });
|
||||
b.add(t);
|
||||
t = new St.Label({ "text": "Bold", style_class: "bold" });
|
||||
b.add(t);
|
||||
t = new St.Label({ "text": "Monospace", style_class: "monospace" });
|
||||
b.add(t);
|
||||
t = new St.Label({ "text": "Italic", style_class: "italic" });
|
||||
b.add(t);
|
||||
t = new St.Label({ "text": "Bold Italic", style_class: "bold italic" });
|
||||
b.add(t);
|
||||
t = new St.Label({ "text": "Big Italic", style_class: "big italic" });
|
||||
b.add(t);
|
||||
t = new St.Label({ "text": "Big Bold", style_class: "big bold" });
|
||||
b.add(t);
|
||||
|
||||
let b2 = new St.BoxLayout({ vertical: true, style_class: "monospace" });
|
||||
b.add(b2);
|
||||
t = new St.Label({ "text": "Big Monospace", style_class: "big" });
|
||||
b2.add(t);
|
||||
t = new St.Label({ "text": "Italic Monospace", style_class: "italic" });
|
||||
b2.add(t);
|
||||
let b2 = new St.BoxLayout({ vertical: true, style_class: "monospace" });
|
||||
b.add(b2);
|
||||
t = new St.Label({ "text": "Big Monospace", style_class: "big" });
|
||||
b2.add(t);
|
||||
t = new St.Label({ "text": "Italic Monospace", style_class: "italic" });
|
||||
b2.add(t);
|
||||
|
||||
stage.show();
|
||||
Clutter.main();
|
||||
UI.main(stage);
|
||||
}
|
||||
test();
|
||||
|
@ -1,32 +1,28 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Lang = imports.lang;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const Calendar = imports.ui.calendar;
|
||||
const UI = imports.testcommon.ui;
|
||||
|
||||
Gtk.init(null, null);
|
||||
function test() {
|
||||
let stage = new Clutter.Stage({ width: 400, height: 400 });
|
||||
UI.init(stage);
|
||||
|
||||
UI.init();
|
||||
let stage = Clutter.Stage.get_default();
|
||||
stage.width = stage.height = 400;
|
||||
stage.show();
|
||||
let vbox = new St.BoxLayout({ vertical: true,
|
||||
width: stage.width,
|
||||
height: stage.height,
|
||||
style: 'padding: 10px; spacing: 10px; font: 15px sans-serif;' });
|
||||
stage.add_actor(vbox);
|
||||
|
||||
let vbox = new St.BoxLayout({ vertical: true,
|
||||
width: stage.width,
|
||||
height: stage.height,
|
||||
style: 'padding: 10px; spacing: 10px; font: 15px sans-serif;' });
|
||||
stage.add_actor(vbox);
|
||||
let entry = new St.Entry({ style: 'border: 1px solid black;' });
|
||||
vbox.add(entry,
|
||||
{ expand: true,
|
||||
y_fill: false, y_align: St.Align.MIDDLE });
|
||||
entry.grab_key_focus();
|
||||
|
||||
let entry = new St.Entry({ style: 'border: 1px solid black;' });
|
||||
vbox.add(entry,
|
||||
{ expand: true,
|
||||
y_fill: false, y_align: St.Align.MIDDLE });
|
||||
entry.grab_key_focus();
|
||||
|
||||
stage.show();
|
||||
Clutter.main();
|
||||
stage.destroy();
|
||||
UI.main(stage);
|
||||
}
|
||||
test();
|
||||
|
@ -5,84 +5,83 @@ const St = imports.gi.St;
|
||||
|
||||
const UI = imports.testcommon.ui;
|
||||
|
||||
UI.init();
|
||||
let stage = Clutter.Stage.get_default();
|
||||
function test() {
|
||||
let stage = new Clutter.Stage();
|
||||
UI.init(stage);
|
||||
|
||||
stage.width = 400;
|
||||
stage.height = 700;
|
||||
let b = new St.BoxLayout({ vertical: true,
|
||||
width: stage.width,
|
||||
height: stage.height });
|
||||
stage.add_actor(b);
|
||||
|
||||
let b = new St.BoxLayout({ vertical: true,
|
||||
width: stage.width,
|
||||
height: stage.height });
|
||||
stage.add_actor(b);
|
||||
function addTest(label, icon_props) {
|
||||
if (b.get_children().length > 0)
|
||||
b.add (new St.BoxLayout({ style: 'background: #cccccc; border: 10px transparent white; height: 1px; ' }));
|
||||
|
||||
function addTest(label, icon_props) {
|
||||
if (b.get_children().length > 0)
|
||||
b.add (new St.BoxLayout({ style: 'background: #cccccc; border: 10px transparent white; height: 1px; ' }));
|
||||
let hb = new St.BoxLayout({ vertical: false,
|
||||
style: 'spacing: 10px;' });
|
||||
|
||||
let hb = new St.BoxLayout({ vertical: false,
|
||||
style: 'spacing: 10px;' });
|
||||
hb.add(new St.Label({ text: label }), { y_fill: false });
|
||||
hb.add(new St.Icon(icon_props));
|
||||
|
||||
hb.add(new St.Label({ text: label }), { y_fill: false });
|
||||
hb.add(new St.Icon(icon_props));
|
||||
|
||||
b.add(hb);
|
||||
}
|
||||
|
||||
addTest("Symbolic",
|
||||
{ icon_name: 'battery-full',
|
||||
icon_type: St.IconType.SYMBOLIC,
|
||||
icon_size: 48 });
|
||||
addTest("Full color",
|
||||
{ icon_name: 'battery-full',
|
||||
icon_type: St.IconType.FULLCOLOR,
|
||||
icon_size: 48 });
|
||||
addTest("Default size",
|
||||
{ icon_name: 'battery-full',
|
||||
icon_type: St.IconType.SYMBOLIC });
|
||||
addTest("Size set by property",
|
||||
{ icon_name: 'battery-full',
|
||||
icon_type: St.IconType.SYMBOLIC,
|
||||
icon_size: 32 });
|
||||
addTest("Size set by style",
|
||||
{ icon_name: 'battery-full',
|
||||
icon_type: St.IconType.SYMBOLIC,
|
||||
style: 'icon-size: 1em;' });
|
||||
addTest("16px icon in 48px icon widget",
|
||||
{ icon_name: 'battery-full',
|
||||
icon_type: St.IconType.SYMBOLIC,
|
||||
style: 'icon-size: 16px; width: 48px; height: 48px; border: 1px solid black;' });
|
||||
|
||||
function iconRow(icons, box_style) {
|
||||
let hb = new St.BoxLayout({ vertical: false, style: box_style });
|
||||
|
||||
for each (let iconName in icons) {
|
||||
hb.add(new St.Icon({ icon_name: iconName,
|
||||
icon_type: St.IconType.SYMBOLIC,
|
||||
icon_size: 48 }));
|
||||
b.add(hb);
|
||||
}
|
||||
|
||||
b.add(hb);
|
||||
addTest("Symbolic",
|
||||
{ icon_name: 'battery-full',
|
||||
icon_type: St.IconType.SYMBOLIC,
|
||||
icon_size: 48 });
|
||||
addTest("Full color",
|
||||
{ icon_name: 'battery-full',
|
||||
icon_type: St.IconType.FULLCOLOR,
|
||||
icon_size: 48 });
|
||||
addTest("Default size",
|
||||
{ icon_name: 'battery-full',
|
||||
icon_type: St.IconType.SYMBOLIC });
|
||||
addTest("Size set by property",
|
||||
{ icon_name: 'battery-full',
|
||||
icon_type: St.IconType.SYMBOLIC,
|
||||
icon_size: 32 });
|
||||
addTest("Size set by style",
|
||||
{ icon_name: 'battery-full',
|
||||
icon_type: St.IconType.SYMBOLIC,
|
||||
style: 'icon-size: 1em;' });
|
||||
addTest("16px icon in 48px icon widget",
|
||||
{ icon_name: 'battery-full',
|
||||
icon_type: St.IconType.SYMBOLIC,
|
||||
style: 'icon-size: 16px; width: 48px; height: 48px; border: 1px solid black;' });
|
||||
|
||||
function iconRow(icons, box_style) {
|
||||
let hb = new St.BoxLayout({ vertical: false, style: box_style });
|
||||
|
||||
for each (let iconName in icons) {
|
||||
hb.add(new St.Icon({ icon_name: iconName,
|
||||
icon_type: St.IconType.SYMBOLIC,
|
||||
icon_size: 48 }));
|
||||
}
|
||||
|
||||
b.add(hb);
|
||||
}
|
||||
|
||||
let normalCss = 'background: white; color: black; padding: 10px 10px;';
|
||||
let reversedCss = 'background: black; color: white; warning-color: #ffcc00; error-color: #ff0000; padding: 10px 10px;';
|
||||
|
||||
let batteryIcons = ['battery-full-charging',
|
||||
'battery-full',
|
||||
'battery-good',
|
||||
'battery-low',
|
||||
'battery-caution' ];
|
||||
|
||||
let volumeIcons = ['audio-volume-high',
|
||||
'audio-volume-medium',
|
||||
'audio-volume-low',
|
||||
'audio-volume-muted' ];
|
||||
|
||||
iconRow(batteryIcons, normalCss);
|
||||
iconRow(batteryIcons, reversedCss);
|
||||
iconRow(volumeIcons, normalCss);
|
||||
iconRow(volumeIcons, reversedCss);
|
||||
|
||||
UI.main(stage);
|
||||
}
|
||||
|
||||
let normalCss = 'background: white; color: black; padding: 10px 10px;';
|
||||
let reversedCss = 'background: black; color: white; warning-color: #ffcc00; error-color: #ff0000; padding: 10px 10px;';
|
||||
|
||||
let batteryIcons = ['battery-full-charging',
|
||||
'battery-full',
|
||||
'battery-good',
|
||||
'battery-low',
|
||||
'battery-caution' ];
|
||||
|
||||
let volumeIcons = ['audio-volume-high',
|
||||
'audio-volume-medium',
|
||||
'audio-volume-low',
|
||||
'audio-volume-muted' ];
|
||||
|
||||
iconRow(batteryIcons, normalCss);
|
||||
iconRow(batteryIcons, reversedCss);
|
||||
iconRow(volumeIcons, normalCss);
|
||||
iconRow(volumeIcons, reversedCss);
|
||||
|
||||
stage.show();
|
||||
Clutter.main();
|
||||
test();
|
||||
|
@ -5,43 +5,43 @@ const St = imports.gi.St;
|
||||
|
||||
const UI = imports.testcommon.ui;
|
||||
|
||||
UI.init();
|
||||
let stage = Clutter.Stage.get_default();
|
||||
function test() {
|
||||
let stage = new Clutter.Stage();
|
||||
UI.init(stage);
|
||||
|
||||
let vbox = new St.BoxLayout({ vertical: true,
|
||||
width: stage.width,
|
||||
height: stage.height });
|
||||
stage.add_actor(vbox);
|
||||
let vbox = new St.BoxLayout({ vertical: true,
|
||||
width: stage.width,
|
||||
height: stage.height });
|
||||
stage.add_actor(vbox);
|
||||
|
||||
let hbox = new St.BoxLayout({ style: 'spacing: 12px;' });
|
||||
vbox.add(hbox);
|
||||
let hbox = new St.BoxLayout({ style: 'spacing: 12px;' });
|
||||
vbox.add(hbox);
|
||||
|
||||
let text = new St.Label({ text: "Styled Text" });
|
||||
vbox.add (text);
|
||||
let text = new St.Label({ text: "Styled Text" });
|
||||
vbox.add (text);
|
||||
|
||||
let size = 24;
|
||||
function update_size() {
|
||||
text.style = 'font-size: ' + size + 'pt';
|
||||
let size = 24;
|
||||
function update_size() {
|
||||
text.style = 'font-size: ' + size + 'pt';
|
||||
}
|
||||
update_size();
|
||||
|
||||
let button;
|
||||
|
||||
button = new St.Button ({ label: 'Smaller', style_class: 'push-button' });
|
||||
hbox.add (button);
|
||||
button.connect('clicked', function() {
|
||||
size /= 1.2;
|
||||
update_size ();
|
||||
});
|
||||
|
||||
button = new St.Button ({ label: 'Bigger', style_class: 'push-button' });
|
||||
hbox.add (button);
|
||||
button.connect('clicked', function() {
|
||||
size *= 1.2;
|
||||
update_size ();
|
||||
});
|
||||
|
||||
UI.main(stage);
|
||||
}
|
||||
update_size();
|
||||
|
||||
let button;
|
||||
|
||||
button = new St.Button ({ label: 'Smaller', style_class: 'push-button' });
|
||||
hbox.add (button);
|
||||
button.connect('clicked', function() {
|
||||
size /= 1.2;
|
||||
update_size ();
|
||||
});
|
||||
|
||||
button = new St.Button ({ label: 'Bigger', style_class: 'push-button' });
|
||||
hbox.add (button);
|
||||
button.connect('clicked', function() {
|
||||
size *= 1.2;
|
||||
update_size ();
|
||||
});
|
||||
|
||||
stage.show();
|
||||
Clutter.main();
|
||||
stage.destroy();
|
||||
|
||||
test();
|
||||
|
@ -251,140 +251,139 @@ SizingIllustrator.prototype = {
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
UI.init();
|
||||
let stage = Clutter.Stage.get_default();
|
||||
stage.width = 600;
|
||||
stage.height = 600;
|
||||
function test() {
|
||||
let stage = new Clutter.Stage({ width: 600, height: 600 });
|
||||
UI.init(stage);
|
||||
|
||||
let mainBox = new St.BoxLayout({ width: stage.width,
|
||||
height: stage.height,
|
||||
vertical: true,
|
||||
style: 'padding: 10px;'
|
||||
+ 'spacing: 5px;'
|
||||
+ 'font: 16px sans-serif;'
|
||||
+ 'background: black;'
|
||||
+ 'color: white;' });
|
||||
stage.add_actor(mainBox);
|
||||
let mainBox = new St.BoxLayout({ width: stage.width,
|
||||
height: stage.height,
|
||||
vertical: true,
|
||||
style: 'padding: 10px;'
|
||||
+ 'spacing: 5px;'
|
||||
+ 'font: 16px sans-serif;'
|
||||
+ 'background: black;'
|
||||
+ 'color: white;' });
|
||||
stage.add_actor(mainBox);
|
||||
|
||||
const DOCS = 'Red lines represent minimum size, blue lines natural size. Drag yellow handle to resize ScrollView. Click on options to change.';
|
||||
const DOCS = 'Red lines represent minimum size, blue lines natural size. Drag yellow handle to resize ScrollView. Click on options to change.';
|
||||
|
||||
let docsLabel = new St.Label({ text: DOCS });
|
||||
docsLabel.clutter_text.line_wrap = true;
|
||||
mainBox.add(docsLabel);
|
||||
let docsLabel = new St.Label({ text: DOCS });
|
||||
docsLabel.clutter_text.line_wrap = true;
|
||||
mainBox.add(docsLabel);
|
||||
|
||||
let bin = new St.Bin({ x_fill: true, y_fill: true, style: 'border: 2px solid #666666;' });
|
||||
mainBox.add(bin, { x_fill: true, y_fill: true, expand: true });
|
||||
let bin = new St.Bin({ x_fill: true, y_fill: true, style: 'border: 2px solid #666666;' });
|
||||
mainBox.add(bin, { x_fill: true, y_fill: true, expand: true });
|
||||
|
||||
let illustrator = new SizingIllustrator();
|
||||
bin.add_actor(illustrator.actor);
|
||||
let illustrator = new SizingIllustrator();
|
||||
bin.add_actor(illustrator.actor);
|
||||
|
||||
let scrollView = new St.ScrollView();
|
||||
illustrator.add(scrollView);
|
||||
let scrollView = new St.ScrollView();
|
||||
illustrator.add(scrollView);
|
||||
|
||||
let box = new St.BoxLayout({ vertical: true });
|
||||
scrollView.add_actor(box);
|
||||
let box = new St.BoxLayout({ vertical: true });
|
||||
scrollView.add_actor(box);
|
||||
|
||||
let flowedBoxes = new FlowedBoxes();
|
||||
box.add(flowedBoxes.actor, { expand: false, x_fill: true, y_fill: true });
|
||||
let flowedBoxes = new FlowedBoxes();
|
||||
box.add(flowedBoxes.actor, { expand: false, x_fill: true, y_fill: true });
|
||||
|
||||
let policyBox = new St.BoxLayout({ vertical: false });
|
||||
mainBox.add(policyBox);
|
||||
let policyBox = new St.BoxLayout({ vertical: false });
|
||||
mainBox.add(policyBox);
|
||||
|
||||
policyBox.add(new St.Label({ text: 'Horizontal Policy: ' }));
|
||||
let hpolicy = new St.Button({ label: 'AUTOMATIC', style: 'text-decoration: underline; color: #4444ff;' });
|
||||
policyBox.add(hpolicy);
|
||||
policyBox.add(new St.Label({ text: 'Horizontal Policy: ' }));
|
||||
let hpolicy = new St.Button({ label: 'AUTOMATIC', style: 'text-decoration: underline; color: #4444ff;' });
|
||||
policyBox.add(hpolicy);
|
||||
|
||||
let spacer = new St.Bin();
|
||||
policyBox.add(spacer, { expand: true });
|
||||
let spacer = new St.Bin();
|
||||
policyBox.add(spacer, { expand: true });
|
||||
|
||||
policyBox.add(new St.Label({ text: 'Vertical Policy: '}));
|
||||
let vpolicy = new St.Button({ label: 'AUTOMATIC', style: 'text-decoration: underline; color: #4444ff;' });
|
||||
policyBox.add(vpolicy);
|
||||
policyBox.add(new St.Label({ text: 'Vertical Policy: '}));
|
||||
let vpolicy = new St.Button({ label: 'AUTOMATIC', style: 'text-decoration: underline; color: #4444ff;' });
|
||||
policyBox.add(vpolicy);
|
||||
|
||||
function togglePolicy(button) {
|
||||
switch(button.label) {
|
||||
case 'AUTOMATIC':
|
||||
button.label = 'ALWAYS';
|
||||
break;
|
||||
case 'ALWAYS':
|
||||
button.label = 'NEVER';
|
||||
break;
|
||||
case 'NEVER':
|
||||
button.label = 'AUTOMATIC';
|
||||
break;
|
||||
function togglePolicy(button) {
|
||||
switch(button.label) {
|
||||
case 'AUTOMATIC':
|
||||
button.label = 'ALWAYS';
|
||||
break;
|
||||
case 'ALWAYS':
|
||||
button.label = 'NEVER';
|
||||
break;
|
||||
case 'NEVER':
|
||||
button.label = 'AUTOMATIC';
|
||||
break;
|
||||
}
|
||||
scrollView.set_policy(Gtk.PolicyType[hpolicy.label], Gtk.PolicyType[vpolicy.label]);
|
||||
}
|
||||
scrollView.set_policy(Gtk.PolicyType[hpolicy.label], Gtk.PolicyType[vpolicy.label]);
|
||||
}
|
||||
|
||||
hpolicy.connect('clicked', function() { togglePolicy(hpolicy); });
|
||||
vpolicy.connect('clicked', function() { togglePolicy(vpolicy); });
|
||||
hpolicy.connect('clicked', function() { togglePolicy(hpolicy); });
|
||||
vpolicy.connect('clicked', function() { togglePolicy(vpolicy); });
|
||||
|
||||
let fadeBox = new St.BoxLayout({ vertical: false });
|
||||
mainBox.add(fadeBox);
|
||||
let fadeBox = new St.BoxLayout({ vertical: false });
|
||||
mainBox.add(fadeBox);
|
||||
|
||||
spacer = new St.Bin();
|
||||
fadeBox.add(spacer, { expand: true });
|
||||
spacer = new St.Bin();
|
||||
fadeBox.add(spacer, { expand: true });
|
||||
|
||||
fadeBox.add(new St.Label({ text: 'Padding: '}));
|
||||
let paddingButton = new St.Button({ label: 'No', style: 'text-decoration: underline; color: #4444ff;padding-right:3px;' });
|
||||
fadeBox.add(paddingButton);
|
||||
fadeBox.add(new St.Label({ text: 'Padding: '}));
|
||||
let paddingButton = new St.Button({ label: 'No', style: 'text-decoration: underline; color: #4444ff;padding-right:3px;' });
|
||||
fadeBox.add(paddingButton);
|
||||
|
||||
fadeBox.add(new St.Label({ text: 'Borders: '}));
|
||||
let borderButton = new St.Button({ label: 'No', style: 'text-decoration: underline; color: #4444ff;padding-right:3px;' });
|
||||
fadeBox.add(borderButton);
|
||||
fadeBox.add(new St.Label({ text: 'Borders: '}));
|
||||
let borderButton = new St.Button({ label: 'No', style: 'text-decoration: underline; color: #4444ff;padding-right:3px;' });
|
||||
fadeBox.add(borderButton);
|
||||
|
||||
fadeBox.add(new St.Label({ text: 'Vertical Fade: '}));
|
||||
let vfade = new St.Button({ label: 'No', style: 'text-decoration: underline; color: #4444ff;' });
|
||||
fadeBox.add(vfade);
|
||||
fadeBox.add(new St.Label({ text: 'Vertical Fade: '}));
|
||||
let vfade = new St.Button({ label: 'No', style: 'text-decoration: underline; color: #4444ff;' });
|
||||
fadeBox.add(vfade);
|
||||
|
||||
function togglePadding(button) {
|
||||
switch(button.label) {
|
||||
case 'No':
|
||||
button.label = 'Yes';
|
||||
break;
|
||||
case 'Yes':
|
||||
button.label = 'No';
|
||||
break;
|
||||
function togglePadding(button) {
|
||||
switch(button.label) {
|
||||
case 'No':
|
||||
button.label = 'Yes';
|
||||
break;
|
||||
case 'Yes':
|
||||
button.label = 'No';
|
||||
break;
|
||||
}
|
||||
if (scrollView.style == null)
|
||||
scrollView.style = (button.label == 'Yes' ? 'padding: 10px;' : 'padding: 0;');
|
||||
else
|
||||
scrollView.style += (button.label == 'Yes' ? 'padding: 10px;' : 'padding: 0;');
|
||||
}
|
||||
if (scrollView.style == null)
|
||||
scrollView.style = (button.label == 'Yes' ? 'padding: 10px;' : 'padding: 0;');
|
||||
else
|
||||
scrollView.style += (button.label == 'Yes' ? 'padding: 10px;' : 'padding: 0;');
|
||||
}
|
||||
|
||||
paddingButton.connect('clicked', function() { togglePadding(paddingButton); });
|
||||
paddingButton.connect('clicked', function() { togglePadding(paddingButton); });
|
||||
|
||||
function toggleBorders(button) {
|
||||
switch(button.label) {
|
||||
case 'No':
|
||||
button.label = 'Yes';
|
||||
break;
|
||||
case 'Yes':
|
||||
button.label = 'No';
|
||||
break;
|
||||
function toggleBorders(button) {
|
||||
switch(button.label) {
|
||||
case 'No':
|
||||
button.label = 'Yes';
|
||||
break;
|
||||
case 'Yes':
|
||||
button.label = 'No';
|
||||
break;
|
||||
}
|
||||
if (scrollView.style == null)
|
||||
scrollView.style = (button.label == 'Yes' ? 'border: 2px solid red;' : 'border: 0;');
|
||||
else
|
||||
scrollView.style += (button.label == 'Yes' ? 'border: 2px solid red;' : 'border: 0;');
|
||||
}
|
||||
if (scrollView.style == null)
|
||||
scrollView.style = (button.label == 'Yes' ? 'border: 2px solid red;' : 'border: 0;');
|
||||
else
|
||||
scrollView.style += (button.label == 'Yes' ? 'border: 2px solid red;' : 'border: 0;');
|
||||
}
|
||||
|
||||
borderButton.connect('clicked', function() { toggleBorders(borderButton); });
|
||||
borderButton.connect('clicked', function() { toggleBorders(borderButton); });
|
||||
|
||||
function toggleFade(button) {
|
||||
switch(button.label) {
|
||||
case 'No':
|
||||
button.label = 'Yes';
|
||||
break;
|
||||
case 'Yes':
|
||||
button.label = 'No';
|
||||
break;
|
||||
function toggleFade(button) {
|
||||
switch(button.label) {
|
||||
case 'No':
|
||||
button.label = 'Yes';
|
||||
break;
|
||||
case 'Yes':
|
||||
button.label = 'No';
|
||||
break;
|
||||
}
|
||||
scrollView.set_style_class_name(button.label == 'Yes' ? 'vfade' : '');
|
||||
}
|
||||
scrollView.set_style_class_name(button.label == 'Yes' ? 'vfade' : '');
|
||||
|
||||
vfade.connect('clicked', function() { toggleFade(vfade); });
|
||||
|
||||
UI.main(stage);
|
||||
}
|
||||
|
||||
vfade.connect('clicked', function() { toggleFade(vfade); });
|
||||
|
||||
stage.show();
|
||||
Clutter.main();
|
||||
stage.destroy();
|
||||
test();
|
||||
|
@ -6,47 +6,48 @@ const St = imports.gi.St;
|
||||
|
||||
const UI = imports.testcommon.ui;
|
||||
|
||||
UI.init();
|
||||
let stage = Clutter.Stage.get_default();
|
||||
function test() {
|
||||
let stage = new Clutter.Stage();
|
||||
UI.init(stage);
|
||||
|
||||
let vbox = new St.BoxLayout({ vertical: true,
|
||||
width: stage.width,
|
||||
height: stage.height,
|
||||
style: "padding: 10px;" });
|
||||
stage.add_actor(vbox);
|
||||
let vbox = new St.BoxLayout({ vertical: true,
|
||||
width: stage.width,
|
||||
height: stage.height,
|
||||
style: "padding: 10px;" });
|
||||
stage.add_actor(vbox);
|
||||
|
||||
let toggle = new St.Button({ label: 'Horizontal Scrolling',
|
||||
toggle_mode: true });
|
||||
vbox.add(toggle);
|
||||
let toggle = new St.Button({ label: 'Horizontal Scrolling',
|
||||
toggle_mode: true });
|
||||
vbox.add(toggle);
|
||||
|
||||
let v = new St.ScrollView();
|
||||
vbox.add(v, { expand: true });
|
||||
let v = new St.ScrollView();
|
||||
vbox.add(v, { expand: true });
|
||||
|
||||
toggle.connect('notify::checked', function () {
|
||||
v.set_policy(toggle.checked ? Gtk.PolicyType.AUTOMATIC
|
||||
: Gtk.PolicyType.NEVER,
|
||||
Gtk.PolicyType.AUTOMATIC);
|
||||
});
|
||||
toggle.connect('notify::checked', function () {
|
||||
v.set_policy(toggle.checked ? Gtk.PolicyType.AUTOMATIC
|
||||
: Gtk.PolicyType.NEVER,
|
||||
Gtk.PolicyType.AUTOMATIC);
|
||||
});
|
||||
|
||||
let b = new St.BoxLayout({ vertical: true,
|
||||
style: "border: 2px solid #880000; border-radius: 10px; padding: 0px 5px;" });
|
||||
v.add_actor(b);
|
||||
let b = new St.BoxLayout({ vertical: true,
|
||||
style: "border: 2px solid #880000; border-radius: 10px; padding: 0px 5px;" });
|
||||
v.add_actor(b);
|
||||
|
||||
let cc_a = "a".charCodeAt(0);
|
||||
let s = "";
|
||||
for (let i = 0; i < 26 * 3; i++) {
|
||||
s += String.fromCharCode(cc_a + i % 26);
|
||||
let cc_a = "a".charCodeAt(0);
|
||||
let s = "";
|
||||
for (let i = 0; i < 26 * 3; i++) {
|
||||
s += String.fromCharCode(cc_a + i % 26);
|
||||
|
||||
let t = new St.Label({ text: s,
|
||||
reactive: true });
|
||||
let line = i + 1;
|
||||
t.connect('button-press-event',
|
||||
function() {
|
||||
log("Click on line " + line);
|
||||
});
|
||||
b.add(t);
|
||||
let t = new St.Label({ text: s,
|
||||
reactive: true });
|
||||
let line = i + 1;
|
||||
t.connect('button-press-event',
|
||||
function() {
|
||||
log("Click on line " + line);
|
||||
});
|
||||
b.add(t);
|
||||
}
|
||||
|
||||
UI.main(stage);
|
||||
}
|
||||
|
||||
stage.show();
|
||||
Clutter.main();
|
||||
stage.destroy();
|
||||
test();
|
||||
|
@ -5,52 +5,53 @@ const St = imports.gi.St;
|
||||
|
||||
const UI = imports.testcommon.ui;
|
||||
|
||||
UI.init();
|
||||
let stage = Clutter.Stage.get_default();
|
||||
stage.width = stage.height = 600;
|
||||
function test() {
|
||||
let stage = new Clutter.Stage({ width: 600, height: 600 });
|
||||
UI.init(stage);
|
||||
|
||||
let vbox = new St.BoxLayout({ vertical: true,
|
||||
width: stage.width,
|
||||
height: stage.height,
|
||||
style: 'padding: 10px; '
|
||||
+ 'spacing: 10px;'
|
||||
+ 'font: 15px sans-serif;' });
|
||||
stage.add_actor(vbox);
|
||||
let vbox = new St.BoxLayout({ vertical: true,
|
||||
width: stage.width,
|
||||
height: stage.height,
|
||||
style: 'padding: 10px; '
|
||||
+ 'spacing: 10px;'
|
||||
+ 'font: 15px sans-serif;' });
|
||||
stage.add_actor(vbox);
|
||||
|
||||
function L(text, color) {
|
||||
return new St.Label({ text: text,
|
||||
style: "background: " + color + ";"
|
||||
+ "border: 1px solid rgba(0,0,0,0.5);"
|
||||
+ "padding: 1em;" });
|
||||
function L(text, color) {
|
||||
return new St.Label({ text: text,
|
||||
style: "background: " + color + ";"
|
||||
+ "border: 1px solid rgba(0,0,0,0.5);"
|
||||
+ "padding: 1em;" });
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
let table = new St.Table({ style: "border: 10px solid #888888;"
|
||||
+ "padding: 10px;"
|
||||
+ "spacing-rows: 5px;"
|
||||
+ "spacing-columns: 15px;" });
|
||||
vbox.add(table, { expand: true });
|
||||
|
||||
table.add(L("1", "#ff0000"),
|
||||
{ row: 0, col: 0, col_span: 3 });
|
||||
table.add(L("2", "#00ff00"),
|
||||
{ row: 1, col: 0, row_span: 2 });
|
||||
table.add(L("3", "#0000ff"),
|
||||
{ row: 1, col: 1,
|
||||
x_expand: 0 });
|
||||
table.add(L("4", "#ffff00"),
|
||||
{ row: 1, col: 2,
|
||||
y_expand: 0, y_fill: 0
|
||||
});
|
||||
table.add(L("5", "#ff00ff"),
|
||||
{ row: 2, col: 1, x_expand: 0 });
|
||||
table.add(L("6", "#00ffff"),
|
||||
{ row: 2, col: 2,
|
||||
x_expand: 0, x_fill: 0, x_align: St.Align.END,
|
||||
y_expand: 0, y_fill: 0, y_align: St.Align.END });
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
UI.main(stage);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
let table = new St.Table({ style: "border: 10px solid #888888;"
|
||||
+ "padding: 10px;"
|
||||
+ "spacing-rows: 5px;"
|
||||
+ "spacing-columns: 15px;" });
|
||||
vbox.add(table, { expand: true });
|
||||
|
||||
table.add(L("1", "#ff0000"),
|
||||
{ row: 0, col: 0, col_span: 3 });
|
||||
table.add(L("2", "#00ff00"),
|
||||
{ row: 1, col: 0, row_span: 2 });
|
||||
table.add(L("3", "#0000ff"),
|
||||
{ row: 1, col: 1,
|
||||
x_expand: 0 });
|
||||
table.add(L("4", "#ffff00"),
|
||||
{ row: 1, col: 2,
|
||||
y_expand: 0, y_fill: 0
|
||||
});
|
||||
table.add(L("5", "#ff00ff"),
|
||||
{ row: 2, col: 1, x_expand: 0 });
|
||||
table.add(L("6", "#00ffff"),
|
||||
{ row: 2, col: 2,
|
||||
x_expand: 0, x_fill: 0, x_align: St.Align.END,
|
||||
y_expand: 0, y_fill: 0, y_align: St.Align.END });
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
stage.show();
|
||||
Clutter.main();
|
||||
test();
|
||||
|
@ -5,30 +5,32 @@ const St = imports.gi.St;
|
||||
|
||||
const UI = imports.testcommon.ui;
|
||||
|
||||
UI.init();
|
||||
let stage = Clutter.Stage.get_default();
|
||||
function test() {
|
||||
let stage = new Clutter.Stage();
|
||||
UI.init(stage);
|
||||
|
||||
let hbox = new St.BoxLayout({ name: 'transition-container',
|
||||
reactive: true,
|
||||
track_hover: true,
|
||||
width: stage.width,
|
||||
height: stage.height,
|
||||
style: 'padding: 10px;'
|
||||
+ 'spacing: 10px;' });
|
||||
stage.add_actor(hbox);
|
||||
let hbox = new St.BoxLayout({ name: 'transition-container',
|
||||
reactive: true,
|
||||
track_hover: true,
|
||||
width: stage.width,
|
||||
height: stage.height,
|
||||
style: 'padding: 10px;'
|
||||
+ 'spacing: 10px;' });
|
||||
stage.add_actor(hbox);
|
||||
|
||||
for (let i = 0; i < 5; i ++) {
|
||||
let label = new St.Label({ text: (i+1).toString(),
|
||||
name: "label" + i,
|
||||
style_class: 'transition-label',
|
||||
reactive: true,
|
||||
track_hover: true });
|
||||
for (let i = 0; i < 5; i ++) {
|
||||
let label = new St.Label({ text: (i+1).toString(),
|
||||
name: "label" + i,
|
||||
style_class: 'transition-label',
|
||||
reactive: true,
|
||||
track_hover: true });
|
||||
|
||||
hbox.add(label, { x_fill: false,
|
||||
y_fill: false });
|
||||
hbox.add(label, { x_fill: false,
|
||||
y_fill: false });
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
UI.main(stage);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
stage.show();
|
||||
Clutter.main();
|
||||
test();
|
||||
|
@ -3,16 +3,21 @@
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const GLib = imports.gi.GLib;
|
||||
const St = imports.gi.St;
|
||||
const Shell = imports.gi.Shell;
|
||||
|
||||
const Environment = imports.ui.environment;
|
||||
|
||||
function init() {
|
||||
function init(stage) {
|
||||
Environment.init();
|
||||
|
||||
let stage = Clutter.Stage.get_default();
|
||||
let context = St.ThemeContext.get_for_stage (stage);
|
||||
let context = St.ThemeContext.get_for_stage(stage);
|
||||
let stylesheetPath = GLib.getenv("GNOME_SHELL_TESTSDIR") + "/testcommon/test.css";
|
||||
let theme = new St.Theme ({ application_stylesheet: stylesheetPath });
|
||||
context.set_theme (theme);
|
||||
let theme = new St.Theme({ application_stylesheet: stylesheetPath });
|
||||
context.set_theme(theme);
|
||||
}
|
||||
|
||||
function main(stage) {
|
||||
stage.show();
|
||||
stage.connect('destroy', function() {
|
||||
Clutter.main_quit();
|
||||
});
|
||||
Clutter.main();
|
||||
}
|
||||
|
Reference in New Issue
Block a user