Compare commits

..

10 Commits
osk ... 3.1.4

Author SHA1 Message Date
60612cace9 Add markup.js to TEST_JS 2011-07-27 19:13:03 -04:00
f057502834 Require GJS 1.29.15 2011-07-27 19:13:03 -04:00
21a1149532 Always include gnome-shell-jhbuild.in in EXTRA_DIST 2011-07-27 19:13:03 -04:00
6724ca4f63 Bump version to 3.1.4
Update NEWS
2011-07-27 19:13:03 -04:00
7a6c25b3fb chrome: Ignore minimized windows when updating visibility
The current check for fullscreen windows ignores the window's
minimization state, so that chrome which is hidden in fullscreen
will always hide if the window on top of the window stack is
fullscreen, even if it is actually minimized.
Instead, skip minimized windows when looking for fullscreen windows.

https://bugzilla.gnome.org/show_bug.cgi?id=655446
2011-07-27 23:40:49 +02:00
0366e320af NotificationDaemon: only remove the source if notification sender is removed from DBus and the application is set
This ensures that we don't remove "notify-send" sources, senders of which are
removed from DBus immediately.
2011-07-27 17:16:05 -04:00
f03793b825 tests: add a test for MessageTray._fixMarkup
https://bugzilla.gnome.org/show_bug.cgi?id=650298
2011-07-27 09:29:03 -04:00
0907f030b4 tests: fix up typelib include paths
The js modules have so many imports back and forth that it's pretty
much guaranteed that if you import even one of them, you'll end up
importing all of them, including ui.status.bluetooth and
ui.status.network. So fix up the typelib include paths the same way
gnome-shell-jhbuild does, so we can find everything.

https://bugzilla.gnome.org/show_bug.cgi?id=650298
2011-07-27 09:29:03 -04:00
7542e68b6f messageTray: improve bad-markup handling
_fixMarkup() was supposed to be ensuring that the markup we passed to
clutter was correct, but it was validating the syntax incorrectly, and
wasn't checking that the markup was valid (or even well-formed). This
is bad because if you pass bad pango markup to
clutter_text_set_markup(), it will g_warn and drop the string on the
floor.

Fix by fixing up the regexps, and then calling Pango.parse_markup() on
the result, and just xml-escaping everything if parse_markup() fails.

https://bugzilla.gnome.org/show_bug.cgi?id=650298
2011-07-27 09:29:03 -04:00
9003a34285 Updated Slovak translation 2011-07-26 15:12:15 +02:00
23 changed files with 717 additions and 1234 deletions

47
NEWS
View File

@ -1,3 +1,50 @@
3.1.4
=====
* Take over inserted media handling and autorun from gnome-session [Cosimo]
* Message Tray
- Display a count of unread notifications on icons
[Jasper, Guillaume; #649356, #654139]
- Only remove icons when the sender quits from D-Bus, not when it
closes its last window [Neha, Marina; #645764]
- Solve problems switching chats between shell and Empathy
[Guillaume; #654237]
- Fix handling of bad GMarkup in messages [Dan; #650298]
- Never show notifications when the screensaver is active [Dan; #654550]
* Telepathy integrationpp
- Implement Telepathy Debug interface to enable empathy-debugger
[Guillaume; #652816]
- Allow approving room invitations, and audio/video calls
[Guillaume; #653740 #653939]
- Send typing notifications [Jonny; #650196]
* Fix selection highlighting for light-on-dark entries [Jasper; #643768]
* Make control-Return in the overview open a new window [Maxim]
* Delay showing the alt-Tab switcher to reduce visual noise when
flipping betweeen windows [Dan; #652346]
* When we have vertically stacked monitors, put the message tray
on the bottom one [Dan; #636963]
* Fix various problems with keynav and the Activities button
[Dan; #641253 #645759]
* Ensure screensaver is locked when switching users [Colin; #654565]
* Improve extension creation tool [Jasper; #653206]
* Fix compatibility with latest GJS [Giovanni; #654349]
* Code cleanups [Adel, Dan, Jasper; #645759 #654577 #654791 #654987]
* Misc bug fixes [Richard, Dan, Florian, Giovanni, Jasper, Marc-Antoine, Rui;
#647175 #649513 #650452 #651082 #653700 #653989 #654105 #654791 #654267
#654269 #654527 #655446]
* Build fixes [Florian, Siegfried; #654300]
Contributors:
Giovanni Campagna, Cosimo Cecchi, Guillaume Desmottes, Neha Doijode,
Maxim Ermilov, Adel Gadllah, Siegfried-Angel Gevatter Pujals, Richard Hughes,
Jonny Lamb, Rui Matos, Florian Müllner, Marc-Antoine Perennou, Colin Walters,
Dan Winship, Marina Zhurakhinskaya
Translations:
Mario Blättermann, Paul Seyfert [de], Jorge González, Daniel Mustieles [es],
Fran Dieguez [gl], Yaron Shahrabani [he], Luca Ferretti [it],
Rudolfs Mazurs [lv], Kjartan Maraas [nb], A S Alam [pa], Yuri Kozlov [ru],
Michal Štrba, Matej Urbančič [sl]
3.1.3 3.1.3
===== =====
* Fix problem with "user theme extension" breaking the CSS for other * Fix problem with "user theme extension" breaking the CSS for other

View File

@ -1,5 +1,5 @@
AC_PREREQ(2.63) AC_PREREQ(2.63)
AC_INIT([gnome-shell],[3.1.3],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell]) AC_INIT([gnome-shell],[3.1.4],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
AC_CONFIG_HEADERS([config.h]) AC_CONFIG_HEADERS([config.h])
AC_CONFIG_SRCDIR([src/shell-global.c]) AC_CONFIG_SRCDIR([src/shell-global.c])
@ -66,7 +66,7 @@ AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
CLUTTER_MIN_VERSION=1.7.5 CLUTTER_MIN_VERSION=1.7.5
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1 GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
GJS_MIN_VERSION=0.7.11 GJS_MIN_VERSION=1.29.15
MUTTER_MIN_VERSION=3.0.0 MUTTER_MIN_VERSION=3.0.0
GTK_MIN_VERSION=3.0.0 GTK_MIN_VERSION=3.0.0
GIO_MIN_VERSION=2.25.9 GIO_MIN_VERSION=2.25.9

View File

@ -62,7 +62,6 @@
<child name="clock" schema="org.gnome.shell.clock"/> <child name="clock" schema="org.gnome.shell.clock"/>
<child name="calendar" schema="org.gnome.shell.calendar"/> <child name="calendar" schema="org.gnome.shell.calendar"/>
<child name="recorder" schema="org.gnome.shell.recorder"/> <child name="recorder" schema="org.gnome.shell.recorder"/>
<child name="keyboard" schema="org.gnome.shell.keyboard"/>
</schema> </schema>
<schema id="org.gnome.shell.calendar" path="/org/gnome/shell/calendar/" <schema id="org.gnome.shell.calendar" path="/org/gnome/shell/calendar/"
@ -76,38 +75,6 @@
</key> </key>
</schema> </schema>
<schema id="org.gnome.shell.keyboard" path="/org/gnome/shell/keyboard/"
gettext-domain="@GETTEXT_PACKAGE@">
<key name="show-keyboard" type="b">
<default>false</default>
<_summary>Show the onscreen keyboard</_summary>
<_description>
If true, display onscreen keyboard.
</_description>
</key>
<key name="keyboard-type" type="s">
<default>'touch'</default>
<_summary>Which keyboard to use</_summary>
<_description>
The type of keyboard to use.
</_description>
</key>
<key name="enable-drag" type="b">
<default>false</default>
<_summary>Enable keyboard dragging</_summary>
<_description>
If true, enable keyboard dragging.
</_description>
</key>
<key name="enable-float" type="b">
<default>false</default>
<_summary>Enable floating keyboard</_summary>
<_description>
If true, enable floating keyboard.
</_description>
</key>
</schema>
<schema id="org.gnome.shell.clock" path="/org/gnome/shell/clock/" <schema id="org.gnome.shell.clock" path="/org/gnome/shell/clock/"
gettext-domain="@GETTEXT_PACKAGE@"> gettext-domain="@GETTEXT_PACKAGE@">
<key name="show-seconds" type="b"> <key name="show-seconds" type="b">

View File

@ -1839,57 +1839,3 @@ StTooltip StLabel {
.magnifier-zoom-region.full-screen { .magnifier-zoom-region.full-screen {
border-width: 0px; border-width: 0px;
} }
/* On-screen Keyboard */
#keyboard {
background: rgba(0,0,0,0.8);
}
.keyboard-layout {
spacing: 10px;
padding: 10px;
}
.keyboard-row {
spacing: 15px;
}
.keyboard-key {
min-height: 30px;
min-width: 30px;
background-gradient-start: rgba(255,245,245,0.4);
background-gradient-end: rgba(105,105,105,0.1);
background-gradient-direction: vertical;
font-size: 14pt;
font-weight: bold;
border-radius: 10px;
border: 2px solid #a0a0a0;
color: white;
}
.keyboard-key:grayed {
color: #808080;
border-color: #808080;
}
.keyboard-key:checked,
.keyboard-key:hover {
background: #303030;
border: 3px solid white;
}
.keyboard-key:active {
background: #808080;
}
.keyboard-subkeys {
color: white;
padding: 5px;
-arrow-border-radius: 10px;
-arrow-background-color: #090909;
-arrow-border-width: 2px;
-arrow-border-color: white;
-arrow-base: 20px;
-arrow-rise: 10px;
}

View File

@ -30,7 +30,6 @@ nobase_dist_js_DATA = \
ui/environment.js \ ui/environment.js \
ui/extensionSystem.js \ ui/extensionSystem.js \
ui/iconGrid.js \ ui/iconGrid.js \
ui/keyboard.js \
ui/layout.js \ ui/layout.js \
ui/lightbox.js \ ui/lightbox.js \
ui/link.js \ ui/link.js \

View File

@ -36,10 +36,6 @@ Chrome.prototype = {
this._trackedActors = []; this._trackedActors = [];
Main.connect('initialized', Lang.bind(this, this._finishInit));
},
_finishInit: function() {
Main.layoutManager.connect('monitors-changed', Main.layoutManager.connect('monitors-changed',
Lang.bind(this, this._relayout)); Lang.bind(this, this._relayout));
global.screen.connect('restacked', global.screen.connect('restacked',
@ -293,6 +289,11 @@ Chrome.prototype = {
for (let i = windows.length - 1; i > -1; i--) { for (let i = windows.length - 1; i > -1; i--) {
let window = windows[i]; let window = windows[i];
// Skip minimized windows
if (!window.showing_on_its_workspace())
continue;
let layer = window.get_meta_window().get_layer(); let layer = window.get_meta_window().get_layer();
if (layer == Meta.StackLayer.FULLSCREEN) { if (layer == Meta.StackLayer.FULLSCREEN) {

View File

@ -1,609 +0,0 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Caribou = imports.gi.Caribou;
const Clutter = imports.gi.Clutter;
const DBus = imports.dbus;
const Gdk = imports.gi.Gdk;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const BoxPointer = imports.ui.boxpointer;
const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
const PopupMenu = imports.ui.popupMenu;
const Tweener = imports.ui.tweener;
const KEYBOARD_SCHEMA = 'org.gnome.shell.keyboard';
const SHOW_KEYBOARD = 'show-keyboard';
const KEYBOARD_TYPE = 'keyboard-type';
const ENABLE_DRAGGABLE = 'enable-drag';
const ENABLE_FLOAT = 'enable-float';
// Key constants taken from Antler
const PRETTY_KEYS = {
'BackSpace': '\u232b',
'space': ' ',
'Return': '\u23ce',
'Caribou_Prefs': '\u2328',
'Caribou_ShiftUp': '\u2b06',
'Caribou_ShiftDown': '\u2b07',
'Caribou_Emoticons': '\u263a',
'Caribou_Symbols': '123',
'Caribou_Symbols_More': '{#*',
'Caribou_Alpha': 'Abc',
'Tab': 'Tab',
'Escape': 'Esc',
'Control_L': 'Ctrl',
'Alt_L': 'Alt'
};
const CaribouKeyboardIface = {
name: 'org.gnome.Caribou.Keyboard',
methods: [ { name: 'Show',
inSignature: '',
outSignature: ''
},
{ name: 'Hide',
inSignature: '',
outSignature: ''
},
{ name: 'SetCursorLocation',
inSignature: 'iiii',
outSignature: ''
},
{ name: 'SetEntryLocation',
inSignature: 'iiii',
outSignature: ''
} ],
properties: [ { name: 'Name',
signature: 's',
access: 'read' } ]
};
function Key() {
this._init.apply(this, arguments);
}
Key.prototype = {
_init : function(key, key_width, key_height) {
this._key = key;
this._width = key_width;
this._height = key_height;
this.actor = this._getKey();
this._extended_keys = this._key.get_extended_keys();
this._extended_keyboard = {};
if (this._key.name == "Control_L" || this._key.name == "Alt_L")
this._key.latch = true;
this._key.connect('key-pressed', Lang.bind(this, function ()
{ this.actor.checked = true }));
this._key.connect('key-released', Lang.bind(this, function ()
{ this.actor.checked = false; }));
if (this._extended_keys.length > 0) {
this._grabbed = false;
this._eventCaptureId = 0;
this._key.connect('notify::show-subkeys', Lang.bind(this, this._onShowSubkeysChanged));
this._boxPointer = new BoxPointer.BoxPointer(St.Side.BOTTOM,
{ x_fill: true,
y_fill: true,
x_align: St.Align.START });
// Adds style to existing keyboard style to avoid repetition
this._boxPointer.actor.add_style_class_name('keyboard-subkeys');
this._getExtendedKeys();
this.actor._extended_keys = this._extended_keyboard;
this._boxPointer.actor.hide();
Main.chrome.addActor(this._boxPointer.actor, { visibleInFullscreen: true,
affectsStruts: false });
}
},
_getKey: function () {
let label = this._key.name;
if (label.length > 1) {
let pretty = PRETTY_KEYS[label];
if (pretty)
label = pretty;
else
label = this._getUnichar(this._key);
}
label = GLib.markup_escape_text(label, -1);
let button = new St.Button ({ label: label, style_class: 'keyboard-key' });
button.width = this._width;
button.key_width = this._key.width;
button.height = this._height;
button.draggable = false;
button.connect('button-press-event', Lang.bind(this, function () { this._key.press(); }));
button.connect('button-release-event', Lang.bind(this, function () { this._key.release(); }));
return button;
},
_getUnichar: function(key) {
let keyval = key.keyval;
let unichar = Gdk.keyval_to_unicode(keyval);
if (unichar) {
return String.fromCharCode(unichar);
} else {
return key.name;
}
},
_getExtendedKeys: function () {
this._extended_keyboard = new St.BoxLayout({ style_class: 'keyboard-layout',
vertical: false });
for (let i = 0; i < this._extended_keys.length; ++i) {
let extended_key = this._extended_keys[i];
let label = this._getUnichar(extended_key);
let key = new St.Button({ label: label, style_class: 'keyboard-key' });
key.extended_key = extended_key;
key.width = this._width;
key.height = this._height;
key.draggable = false;
key.connect('button-press-event', Lang.bind(this, function () { extended_key.press(); }));
key.connect('button-release-event', Lang.bind(this, function () { extended_key.release(); }));
this._extended_keyboard.add(key);
}
this._boxPointer.bin.add_actor(this._extended_keyboard);
},
_onEventCapture: function (actor, event) {
let source = event.get_source();
if (event.type() == Clutter.EventType.BUTTON_PRESS ||
(event.type() == Clutter.EventType.BUTTON_RELEASE && source.draggable)) {
if (this._extended_keyboard.contains(source)) {
if (source.draggable) {
source.extended_key.press();
source.extended_key.release();
}
this._ungrab();
return false;
}
this._boxPointer.actor.hide();
this._ungrab();
return true;
}
return false;
},
_ungrab: function () {
global.stage.disconnect(this._eventCaptureId);
this._eventCaptureId = 0;
this._grabbed = false;
Main.popModal(this.actor);
},
_onShowSubkeysChanged: function () {
if (this._key.show_subkeys) {
this.actor.fake_release();
this._boxPointer.actor.raise_top();
this._boxPointer.setPosition(this.actor, 5, 0.5);
this._boxPointer.show(true);
this.actor.set_hover(false);
if (!this._grabbed) {
Main.pushModal(this.actor);
this._eventCaptureId = global.stage.connect('captured-event', Lang.bind(this, this._onEventCapture));
this._grabbed = true;
}
this._key.release();
} else {
if (this._grabbed)
this._ungrab();
this._boxPointer.hide(true);
}
}
};
function Keyboard() {
this._init.apply(this, arguments);
}
Keyboard.prototype = {
_init: function () {
DBus.session.exportObject('/org/gnome/Caribou/Keyboard', this);
DBus.session.acquire_name('org.gnome.Caribou.Keyboard', 0, null, null);
this.actor = new St.BoxLayout({ name: 'keyboard', vertical: true, reactive: true });
this._keyboardSettings = new Gio.Settings({ schema: KEYBOARD_SCHEMA });
this._keyboardSettings.connect('changed', Lang.bind(this, this._display));
this._setupKeyboard();
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._redraw));
Main.layoutManager.bottomBox.add_actor(this.actor);
},
init: function () {
this._display();
},
_setupKeyboard: function() {
if (this._keyboardNotifyId)
this._keyboard.disconnect(this._keyboardNotifyId);
let children = this.actor.get_children();
for (let i = 0; i < children.length; i++)
children[i].destroy();
this._keyboard = new Caribou.KeyboardModel({ keyboard_type: this._keyboardSettings.get_string(KEYBOARD_TYPE) });
this._groups = {};
this._current_page = null;
// Initialize keyboard key measurements
this._numOfHorizKeys = 0;
this._numOfVertKeys = 0;
this._floatId = 0;
this._addKeys();
this._keyboardNotifyId = this._keyboard.connect('notify::active-group', Lang.bind(this, this._onGroupChanged));
},
_display: function () {
if (this._keyboard.keyboard_type != this._keyboardSettings.get_string(KEYBOARD_TYPE))
this._setupKeyboard();
this._showKeyboard = this._keyboardSettings.get_boolean(SHOW_KEYBOARD);
this._draggable = this._keyboardSettings.get_boolean(ENABLE_DRAGGABLE);
this._floating = this._keyboardSettings.get_boolean(ENABLE_FLOAT);
if (this._floating) {
this._floatId = this.actor.connect('button-press-event', Lang.bind(this, this._startDragging));
this._dragging = false;
}
else
this.actor.disconnect(this._floatId);
if (this._showKeyboard)
this.show();
else {
this.hide();
this.destroySource();
}
},
_startDragging: function (actor, event) {
if (this._dragging) // don't allow two drags at the same time
return;
this._dragging = true;
this._preDragStageMode = global.stage_input_mode;
Clutter.grab_pointer(this.actor);
global.set_stage_input_mode(Shell.StageInputMode.FULLSCREEN);
this._releaseId = this.actor.connect('button-release-event', Lang.bind(this, this._endDragging));
this._motionId = this.actor.connect('motion-event', Lang.bind(this, this._motionEvent));
[this._dragStartX, this._dragStartY] = event.get_coords();
[this._currentX, this._currentY] = this.actor.get_position();
},
_endDragging: function () {
if (this._dragging) {
this.actor.disconnect(this._releaseId);
this.actor.disconnect(this._motionId);
Clutter.ungrab_pointer();
global.set_stage_input_mode(this._preDragStageMode);
global.unset_cursor();
this._dragging = false;
}
return true;
},
_motionEvent: function(actor, event) {
let absX, absY;
[absX, absY] = event.get_coords();
global.set_cursor(Shell.Cursor.DND_IN_DRAG);
this._moveHandle(absX, absY);
return true;
},
_moveHandle: function (stageX, stageY) {
let x, y;
x = stageX - this._dragStartX + this._currentX;
y = stageY - this._dragStartY + this._currentY;
this.actor.set_position(x,y);
},
_addKeys: function () {
let groups = this._keyboard.get_groups();
for (let i = 0; i < groups.length; ++i) {
let gname = groups[i];
let group = this._keyboard.get_group(gname);
group.connect('notify::active-level', Lang.bind(this, this._onLevelChanged));
let layers = {};
let levels = group.get_levels();
for (let j = 0; j < levels.length; ++j) {
let lname = levels[j];
let level = group.get_level(lname);
let layout = new St.BoxLayout({ style_class: 'keyboard-layout',
vertical: true });
this._loadRows(level, layout);
layers[lname] = layout;
this.actor.add(layout, { x_fill: false });
layout.hide();
}
this._groups[gname] = layers;
}
this._setActiveLayer();
},
_getTrayIcon: function () {
let trayButton = new St.Button ({ label: "tray", style_class: 'keyboard-key' });
trayButton.key_width = 1;
trayButton.connect('button-press-event', Lang.bind(this, function () {
Main.layoutManager.updateForTray();
}));
Main.overview.connect('showing', Lang.bind(this, function () {
trayButton.reactive = false;
trayButton.add_style_pseudo_class('grayed');
}));
Main.overview.connect('hiding', Lang.bind(this, function () {
trayButton.reactive = true;
trayButton.remove_style_pseudo_class('grayed');
}));
return trayButton;
},
_addRows : function (keys, layout) {
let keyboard_row = new St.BoxLayout();
for (let i = 0; i < keys.length; ++i) {
let children = keys[i].get_children();
let right_box = new St.BoxLayout({ style_class: 'keyboard-row' });
let left_box = new St.BoxLayout({ style_class: 'keyboard-row' });
for (let j = 0; j < children.length; ++j) {
if (this._numOfHorizKeys == 0)
this._numOfHorizKeys = children.length;
let key = children[j];
let button = new Key(key, 0, 0);
if (key.align == 'right')
right_box.add(button.actor);
else
left_box.add(button.actor);
if (key.name == "Caribou_Prefs") {
key.connect('key-released', Lang.bind(this, this._onPrefsClick));
// Add new key for hiding message tray
right_box.add(this._getTrayIcon());
}
}
keyboard_row.add(left_box, { expand: true, x_fill: false, x_align: St.Align.START });
keyboard_row.add(right_box, { expand: true, x_fill: false, x_align: St.Align.END });
}
layout.add(keyboard_row);
},
_manageTray: function () {
this.createSource();
},
_onPrefsClick: function () {
this.hide();
this._manageTray();
},
_loadRows : function (level, layout) {
let rows = level.get_rows();
for (let i = 0; i < rows.length; ++i) {
let row = rows[i];
if (this._numOfVertKeys == 0)
this._numOfVertKeys = rows.length;
this._addRows(row.get_columns(), layout);
}
},
_redraw: function () {
let monitor = Main.layoutManager.bottomMonitor;
let maxHeight = monitor.height / 3;
this.actor.width = monitor.width;
let layout = this._current_page;
let verticalSpacing = layout.get_theme_node().get_length('spacing');
let padding = layout.get_theme_node().get_length('padding');
let box = layout.get_children()[0].get_children()[0];
let horizontalSpacing = box.get_theme_node().get_length('spacing');
let allHorizontalSpacing = (this._numOfHorizKeys - 1) * horizontalSpacing;
let keyWidth = Math.floor((this.actor.width - allHorizontalSpacing - 2 * padding) / this._numOfHorizKeys);
let allVerticalSpacing = (this._numOfVertKeys - 1) * verticalSpacing;
let keyHeight = Math.floor((maxHeight - allVerticalSpacing - 2 * padding) / this._numOfVertKeys);
let keySize = Math.min(keyWidth, keyHeight);
this.actor.height = keySize * this._numOfVertKeys + allVerticalSpacing + 2 * padding;
let rows = this._current_page.get_children();
for (let i = 0; i < rows.length; ++i) {
let keyboard_row = rows[i];
let boxes = keyboard_row.get_children();
for (let j = 0; j < boxes.length; ++j) {
let keys = boxes[j].get_children();
for (let k = 0; k < keys.length; ++k) {
let child = keys[k];
child.width = keySize * child.key_width;
child.height = keySize;
child.draggable = this._draggable;
if (child._extended_keys) {
let extended_keys = child._extended_keys.get_children();
for (let n = 0; n < extended_keys.length; ++n) {
let extended_key = extended_keys[n];
extended_key.width = keySize;
extended_key.height = keySize;
extended_key.draggable = this._draggable;
}
}
}
}
}
},
_onLevelChanged: function () {
this._setActiveLayer();
this._redraw();
},
_onGroupChanged: function () {
this._setActiveLayer();
this._redraw();
},
_setActiveLayer: function () {
let active_group_name = this._keyboard.active_group;
let active_group = this._keyboard.get_group(active_group_name);
let active_level = active_group.active_level;
let layers = this._groups[active_group_name];
if (this._current_page != null) {
this._current_page.hide();
}
this._current_page = layers[active_level];
this._current_page.show();
},
createSource: function () {
if (this._source == null) {
this._source = new KeyboardSource(this);
Main.messageTray.add(this._source);
}
},
destroySource: function () {
if (this._source) {
this._source.destroy();
this._source = null;
}
},
show: function () {
this._redraw();
Main.layoutManager.showKeyboard();
},
hide: function () {
Main.layoutManager.hideKeyboard();
},
// Window placement method
_updatePosition: function (x, y) {
let primary = Main.layoutManager.primaryMonitor;
x -= this.actor.width / 2;
// Determines bottom/top centered
if (y <= primary.height / 2)
y += this.actor.height / 2;
else
y -= 3 * this.actor.height / 2;
// Accounting for monitor boundaries
if (x < primary.x)
x = primary.x;
if (x + this.actor.width > primary.width)
x = primary.width - this.actor.width;
this.actor.set_position(x, y);
},
_moveTemporarily: function () {
this._currentWindow = global.screen.get_display().focus_window;
let rect = this._currentWindow.get_outer_rect();
this._currentWindow.x = rect.x;
this._currentWindow.y = rect.y;
let newX = this._currentWindow.x;
let newY = 3 * this.actor.height / 2;
this._currentWindow.move_frame(true, newX, newY);
},
_setLocation: function (x, y) {
if (this._floating)
this._updatePosition(x, y);
else {
if (y >= 2 * this.actor.height)
this._moveTemporarily();
}
},
// D-Bus methods
Show: function() {
this.destroySource();
this.show();
},
Hide: function() {
if (this._currentWindow) {
this._currentWindow.move_frame(true, this._currentWindow.x, this._currentWindow.y);
this._currentWindow = null;
}
this.hide();
this._manageTray();
},
SetCursorLocation: function(x, y, w, h) {
this._setLocation(x, y);
},
SetEntryLocation: function(x, y, w, h) {
this._setLocation(x, y);
},
get Name() {
return 'gnome-shell';
}
};
DBus.conformExport(Keyboard.prototype, CaribouKeyboardIface);
function KeyboardSource() {
this._init.apply(this, arguments);
}
KeyboardSource.prototype = {
__proto__: MessageTray.Source.prototype,
_init: function(keyboard) {
this._keyboard = keyboard;
MessageTray.Source.prototype._init.call(this, _("Keyboard"));
this._setSummaryIcon(this.createNotificationIcon());
},
createNotificationIcon: function() {
return new St.Icon({ icon_name: 'input-keyboard',
icon_type: St.IconType.SYMBOLIC,
icon_size: this.ICON_SIZE });
},
handleSummaryClick: function() {
let event = Clutter.get_current_event();
if (event.type() != Clutter.EventType.BUTTON_RELEASE)
return false;
if (event.get_button() != 1)
return false;
this.open();
return true;
},
open: function() {
this._keyboard.show();
this._keyboard.destroySource();
}
};

View File

@ -6,17 +6,8 @@ const Signals = imports.signals;
const St = imports.gi.St; const St = imports.gi.St;
const Main = imports.ui.main; const Main = imports.ui.main;
const Meta = imports.gi.Meta;
const Panel = imports.ui.panel;
const Tweener = imports.ui.tweener; const Tweener = imports.ui.tweener;
const State = {
HIDDEN: 0,
SHOWING: 1,
SHOWN: 2,
HIDING: 3
};
const HOT_CORNER_ACTIVATION_TIMEOUT = 0.5; const HOT_CORNER_ACTIVATION_TIMEOUT = 0.5;
function LayoutManager() { function LayoutManager() {
@ -30,95 +21,8 @@ LayoutManager.prototype = {
this.primaryMonitor = null; this.primaryMonitor = null;
this.primaryIndex = -1; this.primaryIndex = -1;
this._hotCorners = []; this._hotCorners = [];
this.bottomBox = new Clutter.Group();
this.topBox = new Clutter.Group({ clip_to_allocation: true });
this.bottomBox.add_actor(this.topBox);
global.screen.connect('monitors-changed', Lang.bind(this, this._monitorsChanged));
this._updateMonitors(); this._updateMonitors();
Main.connect('layout-initialized', Lang.bind(this, this._initChrome));
Main.connect('main-ui-initialized', Lang.bind(this, this._finishInit));
},
_initChrome: function() {
Main.chrome.addActor(this.bottomBox, { affectsStruts: false,
visibleInFullscreen: true });
},
// _updateHotCorners needs access to Main.panel
_finishInit: function() {
this._updateHotCorners();
this.topBox.height = Main.messageTray.actor.height;
this.topBox.y = - Main.messageTray.actor.height;
this._keyboardState = Main.keyboard.actor.visible ? State.SHOWN : State.HIDDEN;
this._traySummoned = true;
Main.keyboard.actor.connect('allocation-changed', Lang.bind(this, this._reposition));
},
_reposition: function () {
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function () { this._updateForKeyboard(); }));
},
_updateForKeyboard: function () {
if (Tweener.isTweening(this.bottomBox))
return;
this.topBox.y = - Main.messageTray.actor.height;
let bottom = this.bottomMonitor.y + this.bottomMonitor.height;
if (this._keyboardState == State.SHOWN)
this.bottomBox.y = bottom - Main.keyboard.actor.height;
else {
this.bottomBox.y = bottom;
this._keyboardState = State.HIDDEN;
}
},
updateForTray: function () {
if (this._keyboardState == State.SHOWN) {
if (this._traySummoned) {
Main.messageTray.lock();
this._traySummoned = false;
}
else {
Main.messageTray.unlock();
this._traySummoned = true;
}
}
else {
Main.messageTray.unlock();
this._traySummoned = false;
}
},
showKeyboard: function () {
let bottom = this.bottomMonitor.y + this.bottomMonitor.height;
// Keyboard height cannot be found directly since the first
// call to this method may be when Keyboard.Keyboard() has
// not returned; therefore the keyboard would be null
Tweener.addTween(this.bottomBox,
{ y: bottom - Main.keyboard.actor.height,
time: 0.5,
transition: 'easeOutQuad',
});
this._keyboardState = State.SHOWN;
this.updateForTray();
},
hideKeyboard: function () {
let bottom = this.bottomMonitor.y + this.bottomMonitor.height;
Tweener.addTween(this.bottomBox,
{ y: bottom,
time: 0.5,
transition: 'easeOutQuad'
});
this._keyboardState = State.HIDDEN;
this.updateForTray();
}, },
// This is called by Main after everything else is constructed; // This is called by Main after everything else is constructed;
@ -153,9 +57,6 @@ LayoutManager.prototype = {
} }
this.primaryMonitor = this.monitors[this.primaryIndex]; this.primaryMonitor = this.monitors[this.primaryIndex];
this.bottomMonitor = this.monitors[this.bottomIndex]; this.bottomMonitor = this.monitors[this.bottomIndex];
this.bottomBox.set_position(0, this.bottomMonitor.y + this.bottomMonitor.height);
this.bottomBox.width = this.bottomMonitor.width;
}, },
_updateHotCorners: function() { _updateHotCorners: function() {

View File

@ -10,7 +10,6 @@ const Lang = imports.lang;
const Mainloop = imports.mainloop; const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta; const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell; const Shell = imports.gi.Shell;
const Signals = imports.signals;
const St = imports.gi.St; const St = imports.gi.St;
const AutomountManager = imports.ui.automountManager; const AutomountManager = imports.ui.automountManager;
@ -21,7 +20,6 @@ const EndSessionDialog = imports.ui.endSessionDialog;
const PolkitAuthenticationAgent = imports.ui.polkitAuthenticationAgent; const PolkitAuthenticationAgent = imports.ui.polkitAuthenticationAgent;
const Environment = imports.ui.environment; const Environment = imports.ui.environment;
const ExtensionSystem = imports.ui.extensionSystem; const ExtensionSystem = imports.ui.extensionSystem;
const Keyboard = imports.ui.keyboard;
const MessageTray = imports.ui.messageTray; const MessageTray = imports.ui.messageTray;
const Overview = imports.ui.overview; const Overview = imports.ui.overview;
const Panel = imports.ui.panel; const Panel = imports.ui.panel;
@ -47,34 +45,32 @@ let automountManager = null;
let autorunManager = null; let autorunManager = null;
let chrome = null; let chrome = null;
let panel = null; let panel = null;
let hotCorners = [];
let placesManager = null; let placesManager = null;
let overview = null; let overview = null;
let runDialog = null;
let lookingGlass = null;
let wm = null; let wm = null;
let messageTray = null; let messageTray = null;
let notificationDaemon = null; let notificationDaemon = null;
let windowAttentionHandler = null; let windowAttentionHandler = null;
let telepathyClient = null; let telepathyClient = null;
let ctrlAltTabManager = null; let ctrlAltTabManager = null;
let recorder = null;
let shellDBusService = null; let shellDBusService = null;
let modalCount = 0;
let modalActorFocusStack = [];
let uiGroup = null; let uiGroup = null;
let magnifier = null; let magnifier = null;
let xdndHandler = null; let xdndHandler = null;
let statusIconDispatcher = null; let statusIconDispatcher = null;
let keyboard = null;
let layoutManager = null; let layoutManager = null;
let _runDialog = null;
let lookingGlass = null;
let _recorder = null;
let _modalCount = 0;
let _modalActorFocusStack = [];
let _errorLogStack = []; let _errorLogStack = [];
let _startDate; let _startDate;
let _defaultCssStylesheet = null; let _defaultCssStylesheet = null;
let _cssStylesheet = null; let _cssStylesheet = null;
const Main = this; let background = null;
Signals.addSignalMethods(Main)
function start() { function start() {
// Monkey patch utility functions into the global proxy; // Monkey patch utility functions into the global proxy;
@ -136,62 +132,50 @@ function start() {
global.overlay_group.reparent(uiGroup); global.overlay_group.reparent(uiGroup);
global.stage.add_actor(uiGroup); global.stage.add_actor(uiGroup);
// Initialize JS modules. We do this in several steps, so that
// less-fundamental modules can depend on more-fundamental ones.
// Overall layout management
layoutManager = new Layout.LayoutManager(); layoutManager = new Layout.LayoutManager();
chrome = new Chrome.Chrome();
ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
Main.emit('layout-initialized');
// Major UI elements; initialize overview first since both panel
// and messageTray connect to its signals
overview = new Overview.Overview();
panel = new Panel.Panel();
messageTray = new MessageTray.MessageTray();
keyboard = new Keyboard.Keyboard();
Main.emit('main-ui-initialized');
// Now the rest of the JS modules (arbitrarily in alphabetical
// order).
keyboard.init();
magnifier = new Magnifier.Magnifier();
notificationDaemon = new NotificationDaemon.NotificationDaemon();
placesManager = new PlaceDisplay.PlacesManager(); placesManager = new PlaceDisplay.PlacesManager();
statusIconDispatcher = new StatusIconDispatcher.StatusIconDispatcher();
telepathyClient = new TelepathyClient.Client();
windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler();
wm = new WindowManager.WindowManager();
xdndHandler = new XdndHandler.XdndHandler(); xdndHandler = new XdndHandler.XdndHandler();
ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
overview = new Overview.Overview();
chrome = new Chrome.Chrome();
magnifier = new Magnifier.Magnifier();
statusIconDispatcher = new StatusIconDispatcher.StatusIconDispatcher();
panel = new Panel.Panel();
wm = new WindowManager.WindowManager();
messageTray = new MessageTray.MessageTray();
notificationDaemon = new NotificationDaemon.NotificationDaemon();
windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler();
telepathyClient = new TelepathyClient.Client();
automountManager = new AutomountManager.AutomountManager(); automountManager = new AutomountManager.AutomountManager();
autorunManager = new AutorunManager.AutorunManager(); autorunManager = new AutorunManager.AutorunManager();
Main.emit('initialized'); layoutManager.init();
overview.init();
statusIconDispatcher.start(messageTray.actor);
_startDate = new Date(); _startDate = new Date();
let recorderSettings = new Gio.Settings({ schema: 'org.gnome.shell.recorder' }); let recorderSettings = new Gio.Settings({ schema: 'org.gnome.shell.recorder' });
global.screen.connect('toggle-recording', function() { global.screen.connect('toggle-recording', function() {
if (_recorder == null) { if (recorder == null) {
_recorder = new Shell.Recorder({ stage: global.stage }); recorder = new Shell.Recorder({ stage: global.stage });
} }
if (_recorder.is_recording()) { if (recorder.is_recording()) {
_recorder.pause(); recorder.pause();
} else { } else {
// read the parameters from GSettings always in case they have changed // read the parameters from GSettings always in case they have changed
_recorder.set_framerate(recorderSettings.get_int('framerate')); recorder.set_framerate(recorderSettings.get_int('framerate'));
_recorder.set_filename('shell-%d%u-%c.' + recorderSettings.get_string('file-extension')); recorder.set_filename('shell-%d%u-%c.' + recorderSettings.get_string('file-extension'));
let pipeline = recorderSettings.get_string('pipeline'); let pipeline = recorderSettings.get_string('pipeline');
if (!pipeline.match(/^\s*$/)) if (!pipeline.match(/^\s*$/))
_recorder.set_pipeline(pipeline); recorder.set_pipeline(pipeline);
else else
_recorder.set_pipeline(null); recorder.set_pipeline(null);
_recorder.record(); recorder.record();
} }
}); });
@ -207,7 +191,6 @@ function start() {
ExtensionSystem.init(); ExtensionSystem.init();
ExtensionSystem.loadExtensions(); ExtensionSystem.loadExtensions();
// Initialize the panel status area now that extensions are loaded
panel.startStatusArea(); panel.startStatusArea();
panel.startupAnimation(); panel.startupAnimation();
@ -532,7 +515,7 @@ function getWindowActorsForWorkspace(workspaceIndex) {
// all key events will be delivered to the stage, so ::captured-event // all key events will be delivered to the stage, so ::captured-event
// on the stage can be used for global keybindings.) // on the stage can be used for global keybindings.)
function _globalKeyPressHandler(actor, event) { function _globalKeyPressHandler(actor, event) {
if (_modalCount == 0) if (modalCount == 0)
return false; return false;
if (event.type() != Clutter.EventType.KEY_PRESS) if (event.type() != Clutter.EventType.KEY_PRESS)
return false; return false;
@ -557,7 +540,7 @@ function _globalKeyPressHandler(actor, event) {
// Other bindings are only available when the overview is up and // Other bindings are only available when the overview is up and
// no modal dialog is present. // no modal dialog is present.
if (!overview.visible || _modalCount > 1) if (!overview.visible || modalCount > 1)
return false; return false;
// This isn't a Meta.KeyBindingAction yet // This isn't a Meta.KeyBindingAction yet
@ -598,8 +581,8 @@ function _globalKeyPressHandler(actor, event) {
} }
function _findModal(actor) { function _findModal(actor) {
for (let i = 0; i < _modalActorFocusStack.length; i++) { for (let i = 0; i < modalActorFocusStack.length; i++) {
if (_modalActorFocusStack[i].actor == actor) if (modalActorFocusStack[i].actor == actor)
return i; return i;
} }
return -1; return -1;
@ -629,7 +612,7 @@ function pushModal(actor, timestamp) {
if (timestamp == undefined) if (timestamp == undefined)
timestamp = global.get_current_time(); timestamp = global.get_current_time();
if (_modalCount == 0) { if (modalCount == 0) {
if (!global.begin_modal(timestamp)) { if (!global.begin_modal(timestamp)) {
log('pushModal: invocation of begin_modal failed'); log('pushModal: invocation of begin_modal failed');
return false; return false;
@ -638,11 +621,11 @@ function pushModal(actor, timestamp) {
global.set_stage_input_mode(Shell.StageInputMode.FULLSCREEN); global.set_stage_input_mode(Shell.StageInputMode.FULLSCREEN);
_modalCount += 1; modalCount += 1;
let actorDestroyId = actor.connect('destroy', function() { let actorDestroyId = actor.connect('destroy', function() {
let index = _findModal(actor); let index = _findModal(actor);
if (index >= 0) if (index >= 0)
_modalActorFocusStack.splice(index, 1); modalActorFocusStack.splice(index, 1);
}); });
let curFocus = global.stage.get_key_focus(); let curFocus = global.stage.get_key_focus();
let curFocusDestroyId; let curFocusDestroyId;
@ -650,10 +633,10 @@ function pushModal(actor, timestamp) {
curFocusDestroyId = curFocus.connect('destroy', function() { curFocusDestroyId = curFocus.connect('destroy', function() {
let index = _findModal(actor); let index = _findModal(actor);
if (index >= 0) if (index >= 0)
_modalActorFocusStack[index].actor = null; modalActorFocusStack[index].actor = null;
}); });
} }
_modalActorFocusStack.push({ actor: actor, modalActorFocusStack.push({ actor: actor,
focus: curFocus, focus: curFocus,
destroyId: actorDestroyId, destroyId: actorDestroyId,
focusDestroyId: curFocusDestroyId }); focusDestroyId: curFocusDestroyId });
@ -688,28 +671,28 @@ function popModal(actor, timestamp) {
throw new Error('incorrect pop'); throw new Error('incorrect pop');
} }
_modalCount -= 1; modalCount -= 1;
let record = _modalActorFocusStack[focusIndex]; let record = modalActorFocusStack[focusIndex];
record.actor.disconnect(record.destroyId); record.actor.disconnect(record.destroyId);
if (focusIndex == _modalActorFocusStack.length - 1) { if (focusIndex == modalActorFocusStack.length - 1) {
if (record.focus) if (record.focus)
record.focus.disconnect(record.focusDestroyId); record.focus.disconnect(record.focusDestroyId);
global.stage.set_key_focus(record.focus); global.stage.set_key_focus(record.focus);
} else { } else {
let t = _modalActorFocusStack[_modalActorFocusStack.length - 1]; let t = modalActorFocusStack[modalActorFocusStack.length - 1];
if (t.focus) if (t.focus)
t.focus.disconnect(t.focusDestroyId); t.focus.disconnect(t.focusDestroyId);
// Remove from the middle, shift the focus chain up // Remove from the middle, shift the focus chain up
for (let i = _modalActorFocusStack.length - 1; i > focusIndex; i--) { for (let i = modalActorFocusStack.length - 1; i > focusIndex; i--) {
_modalActorFocusStack[i].focus = _modalActorFocusStack[i - 1].focus; modalActorFocusStack[i].focus = modalActorFocusStack[i - 1].focus;
_modalActorFocusStack[i].focusDestroyId = _modalActorFocusStack[i - 1].focusDestroyId; modalActorFocusStack[i].focusDestroyId = modalActorFocusStack[i - 1].focusDestroyId;
} }
} }
_modalActorFocusStack.splice(focusIndex, 1); modalActorFocusStack.splice(focusIndex, 1);
if (_modalCount > 0) if (modalCount > 0)
return; return;
global.end_modal(timestamp); global.end_modal(timestamp);
@ -725,10 +708,10 @@ function createLookingGlass() {
} }
function getRunDialog() { function getRunDialog() {
if (_runDialog == null) { if (runDialog == null) {
_runDialog = new RunDialog.RunDialog(); runDialog = new RunDialog.RunDialog();
} }
return _runDialog; return runDialog;
} }
/** /**

View File

@ -68,14 +68,19 @@ function _fixMarkup(text, allowMarkup) {
// Support &amp;, &quot;, &apos;, &lt; and &gt;, escape all other // Support &amp;, &quot;, &apos;, &lt; and &gt;, escape all other
// occurrences of '&'. // occurrences of '&'.
let _text = text.replace(/&(?!amp;|quot;|apos;|lt;|gt;)/g, '&amp;'); let _text = text.replace(/&(?!amp;|quot;|apos;|lt;|gt;)/g, '&amp;');
// Support <b>, <i>, and <u>, escape anything else // Support <b>, <i>, and <u>, escape anything else
// so it displays as raw markup. // so it displays as raw markup.
return _text.replace(/<(\/?[^biu]>|[^>\/][^>])/g, '&lt;$1'); _text = _text.replace(/<(?!\/?[biu]>)/g, '&lt;');
} else {
// Escape everything try {
let _text = text.replace(/&/g, '&amp;'); Pango.parse_markup(_text, -1, '');
return _text.replace(/</g, '&lt;'); return _text;
} catch (e) {}
} }
// !allowMarkup, or invalid markup
return GLib.markup_escape_text(text, -1);
} }
function URLHighlighter(text, lineWrap, allowMarkup) { function URLHighlighter(text, lineWrap, allowMarkup) {
@ -1301,9 +1306,9 @@ MessageTray.prototype = {
this._focusGrabber.connect('focus-grabbed', Lang.bind(this, this._focusGrabber.connect('focus-grabbed', Lang.bind(this,
function() { function() {
if (this._summaryBoxPointer.bin.child) if (this._summaryBoxPointer.bin.child)
this.lock(); this._lock();
})); }));
this._focusGrabber.connect('focus-ungrabbed', Lang.bind(this, this.unlock)); this._focusGrabber.connect('focus-ungrabbed', Lang.bind(this, this._unlock));
this._focusGrabber.connect('button-pressed', Lang.bind(this, this._focusGrabber.connect('button-pressed', Lang.bind(this,
function(focusGrabber, source) { function(focusGrabber, source) {
if (this._clickedSummaryItem && !this._clickedSummaryItem.actor.contains(source)) if (this._clickedSummaryItem && !this._clickedSummaryItem.actor.contains(source))
@ -1313,7 +1318,7 @@ MessageTray.prototype = {
this._focusGrabber.connect('escape-pressed', Lang.bind(this, this._escapeTray)); this._focusGrabber.connect('escape-pressed', Lang.bind(this, this._escapeTray));
this._trayState = State.HIDDEN; this._trayState = State.HIDDEN;
this._locked = 0; this._locked = false;
this._useLongerTrayLeftTimeout = false; this._useLongerTrayLeftTimeout = false;
this._trayLeftTimeoutId = 0; this._trayLeftTimeoutId = 0;
this._pointerInTray = false; this._pointerInTray = false;
@ -1329,9 +1334,9 @@ MessageTray.prototype = {
this._notificationRemoved = false; this._notificationRemoved = false;
this._reNotifyAfterHideNotification = null; this._reNotifyAfterHideNotification = null;
Main.layoutManager.topBox.add_actor(this.actor); Main.chrome.addActor(this.actor, { affectsStruts: false,
visibleInFullscreen: true });
Main.chrome.trackActor(this._notificationBin); Main.chrome.trackActor(this._notificationBin);
Main.chrome.trackActor(this._summaryBin);
Main.chrome.trackActor(this._summaryBoxPointer.actor); Main.chrome.trackActor(this._summaryBoxPointer.actor);
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._setSizePosition)); Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._setSizePosition));
@ -1341,9 +1346,9 @@ MessageTray.prototype = {
Main.overview.connect('showing', Lang.bind(this, Main.overview.connect('showing', Lang.bind(this,
function() { function() {
this._overviewVisible = true; this._overviewVisible = true;
if (this._locked > 0) { if (this._locked) {
this._unsetClickedSummaryItem(); this._unsetClickedSummaryItem();
this.unlock(); this._unlock();
} else { } else {
this._updateState(); this._updateState();
} }
@ -1351,9 +1356,9 @@ MessageTray.prototype = {
Main.overview.connect('hiding', Lang.bind(this, Main.overview.connect('hiding', Lang.bind(this,
function() { function() {
this._overviewVisible = false; this._overviewVisible = false;
if (this._locked > 0) { if (this._locked) {
this._unsetClickedSummaryItem(); this._unsetClickedSummaryItem();
this.unlock(); this._unlock();
} else { } else {
this._updateState(); this._updateState();
} }
@ -1372,7 +1377,7 @@ MessageTray.prototype = {
_setSizePosition: function() { _setSizePosition: function() {
let monitor = Main.layoutManager.bottomMonitor; let monitor = Main.layoutManager.bottomMonitor;
this.actor.x = monitor.x; this.actor.x = monitor.x;
this.actor.y = -1; this.actor.y = monitor.y + monitor.height - 1;
this.actor.width = monitor.width; this.actor.width = monitor.width;
this._notificationBin.x = 0; this._notificationBin.x = 0;
this._notificationBin.width = monitor.width; this._notificationBin.width = monitor.width;
@ -1524,16 +1529,15 @@ MessageTray.prototype = {
this._notificationQueue.splice(index, 1); this._notificationQueue.splice(index, 1);
}, },
lock: function() { _lock: function() {
this._locked += 1; this._locked = true;
this._updateState();
}, },
unlock: function() { _unlock: function() {
if (this._locked > 0) if (!this._locked)
this._locked -= 1; return;
this._pointerInSummary = false; this._locked = false;
this._pointerInTray = false; this._pointerInTray = this.actor.hover && !this._summaryBoxPointer.bin.hover;
this._updateState(); this._updateState();
}, },
@ -1817,7 +1821,7 @@ MessageTray.prototype = {
}, },
_escapeTray: function() { _escapeTray: function() {
this.unlock(); this._unlock();
this._pointerInTray = false; this._pointerInTray = false;
this._pointerInSummary = false; this._pointerInSummary = false;
this._updateNotificationTimeout(0); this._updateNotificationTimeout(0);
@ -1835,7 +1839,7 @@ MessageTray.prototype = {
let notificationsPending = this._notificationQueue.length > 0 && (!this._busy || notificationUrgent); let notificationsPending = this._notificationQueue.length > 0 && (!this._busy || notificationUrgent);
let notificationPinned = this._pointerInTray && !this._pointerInSummary && !this._notificationRemoved; let notificationPinned = this._pointerInTray && !this._pointerInSummary && !this._notificationRemoved;
let notificationExpanded = this._notificationBin.y < 0; let notificationExpanded = this._notificationBin.y < 0;
let notificationExpired = (this._notificationTimeoutId == 0 && !(this._notification && this._notification.urgency == Urgency.CRITICAL) && !this._pointerInTray && (this._locked == 0)) || this._notificationRemoved; let notificationExpired = (this._notificationTimeoutId == 0 && !(this._notification && this._notification.urgency == Urgency.CRITICAL) && !this._pointerInTray && !this._locked) || this._notificationRemoved;
let canShowNotification = notificationsPending && this._summaryState == State.HIDDEN; let canShowNotification = notificationsPending && this._summaryState == State.HIDDEN;
if (this._notificationState == State.HIDDEN) { if (this._notificationState == State.HIDDEN) {
@ -1851,17 +1855,17 @@ MessageTray.prototype = {
} }
// Summary // Summary
let summarySummoned = this._pointerInSummary || this._overviewVisible || (this._locked > 0); let summarySummoned = this._pointerInSummary || this._overviewVisible;
let summaryPinned = this._summaryTimeoutId != 0 || this._pointerInTray || summarySummoned; let summaryPinned = this._summaryTimeoutId != 0 || this._pointerInTray || summarySummoned || this._locked;
let summaryHovered = this._pointerInTray || this._pointerInSummary; let summaryHovered = this._pointerInTray || this._pointerInSummary;
let summaryVisibleWithNoHover = (this._overviewVisible || this._locked > 0) && !summaryHovered; let summaryVisibleWithNoHover = (this._overviewVisible || this._locked) && !summaryHovered;
let summaryNotificationIsForExpandedSummaryItem = (this._clickedSummaryItem == this._expandedSummaryItem); let summaryNotificationIsForExpandedSummaryItem = (this._clickedSummaryItem == this._expandedSummaryItem);
let notificationsVisible = (this._notificationState == State.SHOWING || let notificationsVisible = (this._notificationState == State.SHOWING ||
this._notificationState == State.SHOWN); this._notificationState == State.SHOWN);
let notificationsDone = !notificationsVisible && !notificationsPending; let notificationsDone = !notificationsVisible && !notificationsPending;
let summaryOptionalInOverview = this._overviewVisible && (this._locked == 0) && !summaryHovered; let summaryOptionalInOverview = this._overviewVisible && !this._locked && !summaryHovered;
let mustHideSummary = (notificationsPending && (notificationUrgent || summaryOptionalInOverview)) let mustHideSummary = (notificationsPending && (notificationUrgent || summaryOptionalInOverview))
|| notificationsVisible; || notificationsVisible;
@ -1945,16 +1949,18 @@ MessageTray.prototype = {
}, },
_showTray: function() { _showTray: function() {
let monitor = Main.layoutManager.bottomMonitor;
this._tween(this.actor, '_trayState', State.SHOWN, this._tween(this.actor, '_trayState', State.SHOWN,
{ y: 0, { y: monitor.y + monitor.height - this.actor.height,
time: ANIMATION_TIME, time: ANIMATION_TIME,
transition: 'easeOutQuad' transition: 'easeOutQuad'
}); });
}, },
_hideTray: function() { _hideTray: function() {
let monitor = Main.layoutManager.bottomMonitor;
this._tween(this.actor, '_trayState', State.HIDDEN, this._tween(this.actor, '_trayState', State.HIDDEN,
{ y: Main.layoutManager.topBox.height - 1, { y: monitor.y + monitor.height - 1,
time: ANIMATION_TIME, time: ANIMATION_TIME,
transition: 'easeOutQuad' transition: 'easeOutQuad'
}); });

View File

@ -97,10 +97,8 @@ NotificationDaemon.prototype = {
this._notifications = {}; this._notifications = {};
this._busProxy = new Bus(); this._busProxy = new Bus();
Main.connect('initialized', Lang.bind(this, function() { Main.statusIconDispatcher.connect('message-icon-added', Lang.bind(this, this._onTrayIconAdded));
Main.statusIconDispatcher.connect('message-icon-added', Lang.bind(this, this._onTrayIconAdded)); Main.statusIconDispatcher.connect('message-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
Main.statusIconDispatcher.connect('message-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
}));
Shell.WindowTracker.get_default().connect('notify::focus-app', Shell.WindowTracker.get_default().connect('notify::focus-app',
Lang.bind(this, this._onFocusAppChanged)); Lang.bind(this, this._onFocusAppChanged));
@ -463,9 +461,11 @@ Source.prototype = {
_onNameVanished: function() { _onNameVanished: function() {
// Destroy the notification source when its sender is removed from DBus. // Destroy the notification source when its sender is removed from DBus.
// Only do so if this.app is set to avoid removing "notify-send" sources, senders
// of which аre removed from DBus immediately.
// Sender being removed from DBus would normally result in a tray icon being removed, // Sender being removed from DBus would normally result in a tray icon being removed,
// so allow the code path that handles the tray icon being removed to handle that case. // so allow the code path that handles the tray icon being removed to handle that case.
if (!this.trayIcon) if (!this.trayIcon && this.app)
this.destroy(); this.destroy();
}, },

View File

@ -153,18 +153,6 @@ Overview.prototype = {
this._coverPane.hide(); this._coverPane.hide();
this._windowSwitchTimeoutId = 0;
this._windowSwitchTimestamp = 0;
this._lastActiveWorkspaceIndex = -1;
this._lastHoveredWindow = null;
this._needsFakePointerEvent = false;
this.workspaces = null;
Main.connect('initialized', Lang.bind(this, this._finishInit));
},
_finishInit: function() {
// XDND // XDND
this._dragMonitor = { this._dragMonitor = {
dragMotion: Lang.bind(this, this._onDragMotion) dragMotion: Lang.bind(this, this._onDragMotion)
@ -173,11 +161,22 @@ Overview.prototype = {
Main.xdndHandler.connect('drag-begin', Lang.bind(this, this._onDragBegin)); Main.xdndHandler.connect('drag-begin', Lang.bind(this, this._onDragBegin));
Main.xdndHandler.connect('drag-end', Lang.bind(this, this._onDragEnd)); Main.xdndHandler.connect('drag-end', Lang.bind(this, this._onDragEnd));
this._windowSwitchTimeoutId = 0;
this._windowSwitchTimestamp = 0;
this._lastActiveWorkspaceIndex = -1;
this._lastHoveredWindow = null;
this._needsFakePointerEvent = false;
this.workspaces = null;
},
// The members we construct that are implemented in JS might
// want to access the overview as Main.overview to connect
// signal handlers and so forth. So we create them after
// construction in this init() method.
init: function() {
this.shellInfo = new ShellInfo(); this.shellInfo = new ShellInfo();
// The members we construct that are implemented in JS might
// want to access the overview as Main.overview to connect
// signal handlers and so forth. So we create them here.
this.viewSelector = new ViewSelector.ViewSelector(); this.viewSelector = new ViewSelector.ViewSelector();
this._group.add_actor(this.viewSelector.actor); this._group.add_actor(this.viewSelector.actor);
@ -450,16 +449,19 @@ Overview.prototype = {
let primary = Main.layoutManager.primaryMonitor; let primary = Main.layoutManager.primaryMonitor;
let rtl = (St.Widget.get_default_direction () == St.TextDirection.RTL); let rtl = (St.Widget.get_default_direction () == St.TextDirection.RTL);
let contentY = Main.panel.actor.height;
let contentHeight = primary.height - contentY - Main.messageTray.actor.height;
this._group.set_position(primary.x, primary.y); this._group.set_position(primary.x, primary.y);
this._group.set_size(primary.width, primary.height); this._group.set_size(primary.width, primary.height);
this._coverPane.set_position(primary.x, primary.y); this._coverPane.set_position(0, contentY);
this._coverPane.set_size(primary.width, primary.height); this._coverPane.set_size(primary.width, contentHeight);
let dashWidth = Math.round(DASH_SPLIT_FRACTION * primary.width); let dashWidth = Math.round(DASH_SPLIT_FRACTION * primary.width);
let viewWidth = primary.width - dashWidth - this._spacing; let viewWidth = primary.width - dashWidth - this._spacing;
let viewHeight = primary.height - 2 * this._spacing; let viewHeight = contentHeight - 2 * this._spacing;
let viewY = primary.y + this._spacing; let viewY = contentY + this._spacing;
let viewX = rtl ? 0 : dashWidth + this._spacing; let viewX = rtl ? 0 : dashWidth + this._spacing;
// Set the dash's x position - y is handled by a constraint // Set the dash's x position - y is handled by a constraint

View File

@ -939,6 +939,9 @@ Panel.prototype = {
corner.actor.set_style_pseudo_class(pseudoClass); corner.actor.set_style_pseudo_class(pseudoClass);
})); }));
Main.statusIconDispatcher.connect('status-icon-added', Lang.bind(this, this._onTrayIconAdded));
Main.statusIconDispatcher.connect('status-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
Main.chrome.addActor(this.actor); Main.chrome.addActor(this.actor);
Main.chrome.addActor(this._leftCorner.actor, { affectsStruts: false, Main.chrome.addActor(this._leftCorner.actor, { affectsStruts: false,
affectsInputRegion: false }); affectsInputRegion: false });
@ -967,11 +970,8 @@ Panel.prototype = {
this._statusArea[role] = indicator; this._statusArea[role] = indicator;
} }
Main.statusIconDispatcher.connect('status-icon-added', Lang.bind(this, this._onTrayIconAdded));
Main.statusIconDispatcher.connect('status-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
// PopupMenuManager depends on menus being added in order for // PopupMenuManager depends on menus being added in order for
// keyboard navigation, so we couldn't add this before // keyboard navigation
this._menus.addMenu(this._userMenu.menu); this._menus.addMenu(this._userMenu.menu);
}, },

View File

@ -40,8 +40,6 @@ const KEY_TEXT_SCALING_FACTOR = 'text-scaling-factor';
const HIGH_CONTRAST_THEME = 'HighContrast'; const HIGH_CONTRAST_THEME = 'HighContrast';
const KEYBOARD_SCHEMA = 'org.gnome.shell.keyboard'
function ATIndicator() { function ATIndicator() {
this._init.apply(this, arguments); this._init.apply(this, arguments);
} }
@ -70,9 +68,9 @@ ATIndicator.prototype = {
// 'screen-reader-enabled'); // 'screen-reader-enabled');
// this.menu.addMenuItem(screenReader); // this.menu.addMenuItem(screenReader);
let screenKeyboard = this._buildItem(_("Screen Keyboard"), KEYBOARD_SCHEMA, // let screenKeyboard = this._buildItem(_("Screen Keyboard"), APPLICATIONS_SCHEMA,
'show-keyboard'); // 'screen-keyboard-enabled');
this.menu.addMenuItem(screenKeyboard); // this.menu.addMenuItem(screenKeyboard);
let visualBell = this._buildItemGConf(_("Visual Alerts"), client, KEY_VISUAL_BELL); let visualBell = this._buildItemGConf(_("Visual Alerts"), client, KEY_VISUAL_BELL);
this.menu.addMenuItem(visualBell); this.menu.addMenuItem(visualBell);

View File

@ -4,7 +4,6 @@ const Lang = imports.lang;
const Shell = imports.gi.Shell; const Shell = imports.gi.Shell;
const Signals = imports.signals; const Signals = imports.signals;
const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray; const MessageTray = imports.ui.messageTray;
const NotificationDaemon = imports.ui.notificationDaemon; const NotificationDaemon = imports.ui.notificationDaemon;
const Util = imports.misc.util; const Util = imports.misc.util;
@ -39,10 +38,10 @@ StatusIconDispatcher.prototype = {
// status icons // status icons
// http://bugzilla.gnome.org/show_bug.cgi=id=621382 // http://bugzilla.gnome.org/show_bug.cgi=id=621382
Util.killall('indicator-application-service'); Util.killall('indicator-application-service');
},
Main.connect('initialized', Lang.bind(this, function() { start: function(themeWidget) {
this._traymanager.manage_stage(global.stage, Main.messageTray.actor); this._traymanager.manage_stage(global.stage, themeWidget);
}));
}, },
_onTrayIconAdded: function(o, icon) { _onTrayIconAdded: function(o, icon) {

View File

@ -551,6 +551,7 @@ WorkspacesDisplay.prototype = {
Lang.bind(this, this._onScrollEvent)); Lang.bind(this, this._onScrollEvent));
this._monitorIndex = Main.layoutManager.primaryIndex; this._monitorIndex = Main.layoutManager.primaryIndex;
this._monitor = Main.layoutManager.monitors[this._monitorIndex];
this._thumbnailsBox = new WorkspaceThumbnail.ThumbnailsBox(); this._thumbnailsBox = new WorkspaceThumbnail.ThumbnailsBox();
controls.add_actor(this._thumbnailsBox.actor); controls.add_actor(this._thumbnailsBox.actor);

669
po/sk.po

File diff suppressed because it is too large Load Diff

View File

@ -28,6 +28,7 @@ CLEANFILES += $(service_DATA)
CLEANFILES += $(gir_DATA) $(typelib_DATA) CLEANFILES += $(gir_DATA) $(typelib_DATA)
bin_SCRIPTS += gnome-shell-extension-tool bin_SCRIPTS += gnome-shell-extension-tool
EXTRA_DIST += gnome-shell-extension-tool.in
bin_PROGRAMS = gnome-shell-real bin_PROGRAMS = gnome-shell-real
if USE_JHBUILD_WRAPPER_SCRIPT if USE_JHBUILD_WRAPPER_SCRIPT
@ -36,6 +37,7 @@ bin_SCRIPTS += gnome-shell-jhbuild
else else
gnome_shell = gnome-shell-real gnome_shell = gnome-shell-real
endif endif
EXTRA_DIST += gnome-shell-jhbuild.in
noinst_DATA = gnome-shell noinst_DATA = gnome-shell
gnome-shell: $(gnome_shell) Makefile gnome-shell: $(gnome_shell) Makefile
@ -65,7 +67,6 @@ gnome-shell-extension-tool: gnome-shell-extension-tool.in Makefile
$(AM_V_GEN) sed $(generated_script_substitutions) $< > $@.tmp && mv $@.tmp $@ && chmod a+x $@ $(AM_V_GEN) sed $(generated_script_substitutions) $< > $@.tmp && mv $@.tmp $@ && chmod a+x $@
CLEANFILES += gnome-shell $(bin_SCRIPTS) CLEANFILES += gnome-shell $(bin_SCRIPTS)
EXTRA_DIST += $(bin_SCRIPTS:=.in)
include Makefile-gdmuser.am include Makefile-gdmuser.am
include Makefile-st.am include Makefile-st.am

View File

@ -32,18 +32,17 @@
#include <clutter/x11/clutter-x11.h> #include <clutter/x11/clutter-x11.h>
#include <gdk/gdkx.h> #include <gdk/gdkx.h>
#include <girepository.h>
#include <gjs/gjs.h> #include <gjs/gjs.h>
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include "shell-global.h" #include "shell-global.h"
#include "shell-global-private.h" #include "shell-global-private.h"
static char **include_path = NULL;
static char *command = NULL; static char *command = NULL;
static GOptionEntry entries[] = { static GOptionEntry entries[] = {
{ "command", 'c', 0, G_OPTION_ARG_STRING, &command, "Program passed in as a string", "COMMAND" }, { "command", 'c', 0, G_OPTION_ARG_STRING, &command, "Program passed in as a string", "COMMAND" },
{ "include-path", 'I', 0, G_OPTION_ARG_STRING_ARRAY, &include_path, "Add the directory DIR to the list of directories to search for js files.", "DIR" },
{ NULL } { NULL }
}; };
@ -131,6 +130,14 @@ main(int argc, char **argv)
clutter_stage_set_title (CLUTTER_STAGE (stage), title); clutter_stage_set_title (CLUTTER_STAGE (stage), title);
g_free (title); g_free (title);
#if HAVE_BLUETOOTH
/* The module imports are all so intertwined that if the test
* imports anything in js/ui, it will probably eventually end up
* pulling in ui/status/bluetooth.js. So we need this.
*/
g_irepository_prepend_search_path (BLUETOOTH_DIR);
#endif
/* evaluate the script */ /* evaluate the script */
error = NULL; error = NULL;
if (!gjs_context_eval (js_context, script, len, if (!gjs_context_eval (js_context, script, len,

View File

@ -18,7 +18,8 @@ TEST_JS = \
testcommon/border-image.png \ testcommon/border-image.png \
testcommon/face-plain.png \ testcommon/face-plain.png \
testcommon/ui.js \ testcommon/ui.js \
unit/format.js unit/format.js \
unit/markup.js
EXTRA_DIST += $(TEST_JS) EXTRA_DIST += $(TEST_JS)
TEST_MISC = \ TEST_MISC = \
@ -28,6 +29,7 @@ EXTRA_DIST += $(TEST_MISC)
run-test.sh: run-test.sh.in run-test.sh: run-test.sh.in
$(AM_V_GEN) sed \ $(AM_V_GEN) sed \
-e "s|@MUTTER_TYPELIB_DIR[@]|$(MUTTER_TYPELIB_DIR)|" \ -e "s|@MUTTER_TYPELIB_DIR[@]|$(MUTTER_TYPELIB_DIR)|" \
-e "s|@JHBUILD_TYPELIBDIR[@]|$(JHBUILD_TYPELIBDIR)|" \
-e "s|@srcdir[@]|$(srcdir)|" \ -e "s|@srcdir[@]|$(srcdir)|" \
$< > $@ && chmod a+x $@ $< > $@ && chmod a+x $@

View File

@ -30,7 +30,7 @@ builddir=`cd $builddir && pwd`
srcdir=$builddir/@srcdir@ srcdir=$builddir/@srcdir@
srcdir=`cd $srcdir && pwd` srcdir=`cd $srcdir && pwd`
GI_TYPELIB_PATH="@MUTTER_TYPELIB_DIR@:$builddir/../src" GI_TYPELIB_PATH="$GI_TYPELIB_PATH${GI_TYPELIB_PATH:+:}@MUTTER_TYPELIB_DIR@:@JHBUILD_TYPELIBDIR@:$builddir/../src"
GJS_PATH="$srcdir:$srcdir/../js" GJS_PATH="$srcdir:$srcdir/../js"
GJS_DEBUG_OUTPUT=stderr GJS_DEBUG_OUTPUT=stderr
$verbose || GJS_DEBUG_TOPICS="JS ERROR;JS LOG" $verbose || GJS_DEBUG_TOPICS="JS ERROR;JS LOG"

142
tests/unit/markup.js Normal file
View File

@ -0,0 +1,142 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
// Test cases for MessageTray markup parsing
const JsUnit = imports.jsUnit;
const Pango = imports.gi.Pango;
const Environment = imports.ui.environment;
Environment.init();
const MessageTray = imports.ui.messageTray;
// Assert that @input, assumed to be markup, gets "fixed" to @output,
// which is valid markup. If @output is null, @input is expected to
// convert to itself
function assertConverts(input, output) {
if (!output)
output = input;
let fixed = MessageTray._fixMarkup(input, true);
JsUnit.assertEquals(output, fixed);
let parsed = false;
try {
Pango.parse_markup(fixed, -1, '');
parsed = true;
} catch (e) {}
JsUnit.assertEquals(true, parsed);
}
// Assert that @input, assumed to be plain text, gets escaped to @output,
// which is valid markup.
function assertEscapes(input, output) {
let fixed = MessageTray._fixMarkup(input, false);
JsUnit.assertEquals(output, fixed);
let parsed = false;
try {
Pango.parse_markup(fixed, -1, '');
parsed = true;
} catch (e) {}
JsUnit.assertEquals(true, parsed);
}
// CORRECT MARKUP
assertConverts('foo');
assertEscapes('foo', 'foo');
assertConverts('<b>foo</b>');
assertEscapes('<b>foo</b>', '&lt;b&gt;foo&lt;/b&gt;');
assertConverts('something <i>foo</i>');
assertEscapes('something <i>foo</i>', 'something &lt;i&gt;foo&lt;/i&gt;');
assertConverts('<u>foo</u> something');
assertEscapes('<u>foo</u> something', '&lt;u&gt;foo&lt;/u&gt; something');
assertConverts('<b>bold</b> <i>italic <u>and underlined</u></i>');
assertEscapes('<b>bold</b> <i>italic <u>and underlined</u></i>', '&lt;b&gt;bold&lt;/b&gt; &lt;i&gt;italic &lt;u&gt;and underlined&lt;/u&gt;&lt;/i&gt;');
assertConverts('this &amp; that');
assertEscapes('this &amp; that', 'this &amp;amp; that');
assertConverts('this &lt; that');
assertEscapes('this &lt; that', 'this &amp;lt; that');
assertConverts('this &lt; that &gt; the other');
assertEscapes('this &lt; that &gt; the other', 'this &amp;lt; that &amp;gt; the other');
assertConverts('this &lt;<i>that</i>&gt;');
assertEscapes('this &lt;<i>that</i>&gt;', 'this &amp;lt;&lt;i&gt;that&lt;/i&gt;&amp;gt;');
assertConverts('<b>this</b> > <i>that</i>');
assertEscapes('<b>this</b> > <i>that</i>', '&lt;b&gt;this&lt;/b&gt; &gt; &lt;i&gt;that&lt;/i&gt;');
// PARTIALLY CORRECT MARKUP
// correct bits are kept, incorrect bits are escaped
// unrecognized entity
assertConverts('<b>smile</b> &#9786;!', '<b>smile</b> &amp;#9786;!');
assertEscapes('<b>smile</b> &#9786;!', '&lt;b&gt;smile&lt;/b&gt; &amp;#9786;!');
// stray '&'; this is really a bug, but it's easier to do it this way
assertConverts('<b>this</b> & <i>that</i>', '<b>this</b> &amp; <i>that</i>');
assertEscapes('<b>this</b> & <i>that</i>', '&lt;b&gt;this&lt;/b&gt; &amp; &lt;i&gt;that&lt;/i&gt;');
// likewise with stray '<'
assertConverts('this < that', 'this &lt; that');
assertEscapes('this < that', 'this &lt; that');
assertConverts('<b>this</b> < <i>that</i>', '<b>this</b> &lt; <i>that</i>');
assertEscapes('<b>this</b> < <i>that</i>', '&lt;b&gt;this&lt;/b&gt; &lt; &lt;i&gt;that&lt;/i&gt;');
assertConverts('this < that > the other', 'this &lt; that > the other');
assertEscapes('this < that > the other', 'this &lt; that &gt; the other');
assertConverts('this <<i>that</i>>', 'this &lt;<i>that</i>>');
assertEscapes('this <<i>that</i>>', 'this &lt;&lt;i&gt;that&lt;/i&gt;&gt;');
// unknown tags
assertConverts('<unknown>tag</unknown>', '&lt;unknown>tag&lt;/unknown>');
assertEscapes('<unknown>tag</unknown>', '&lt;unknown&gt;tag&lt;/unknown&gt;');
// make sure we check beyond the first letter
assertConverts('<bunknown>tag</bunknown>', '&lt;bunknown>tag&lt;/bunknown>');
assertEscapes('<bunknown>tag</bunknown>', '&lt;bunknown&gt;tag&lt;/bunknown&gt;');
// with mix of good and bad, we keep the good and escape the bad
assertConverts('<i>known</i> and <unknown>tag</unknown>', '<i>known</i> and &lt;unknown>tag&lt;/unknown>');
assertEscapes('<i>known</i> and <unknown>tag</unknown>', '&lt;i&gt;known&lt;/i&gt; and &lt;unknown&gt;tag&lt;/unknown&gt;');
// FULLY INCORRECT MARKUP
// (fall back to escaping the whole thing)
// tags not matched up
assertConverts('<b>in<i>com</i>plete', '&lt;b&gt;in&lt;i&gt;com&lt;/i&gt;plete');
assertEscapes('<b>in<i>com</i>plete', '&lt;b&gt;in&lt;i&gt;com&lt;/i&gt;plete');
assertConverts('in<i>com</i>plete</b>', 'in&lt;i&gt;com&lt;/i&gt;plete&lt;/b&gt;');
assertEscapes('in<i>com</i>plete</b>', 'in&lt;i&gt;com&lt;/i&gt;plete&lt;/b&gt;');
// we don't support attributes, and it's too complicated to try
// to escape both start and end tags, so we just treat it as bad
assertConverts('<b>good</b> and <b style=\'bad\'>bad</b>', '&lt;b&gt;good&lt;/b&gt; and &lt;b style=&apos;bad&apos;&gt;bad&lt;/b&gt;');
assertEscapes('<b>good</b> and <b style=\'bad\'>bad</b>', '&lt;b&gt;good&lt;/b&gt; and &lt;b style=&apos;bad&apos;&gt;bad&lt;/b&gt;');
// this is just syntactically invalid
assertConverts('<b>unrecognized</b stuff>', '&lt;b&gt;unrecognized&lt;/b stuff&gt;');
assertEscapes('<b>unrecognized</b stuff>', '&lt;b&gt;unrecognized&lt;/b stuff&gt;');
// mismatched tags
assertConverts('<b>mismatched</i>', '&lt;b&gt;mismatched&lt;/i&gt;');
assertEscapes('<b>mismatched</i>', '&lt;b&gt;mismatched&lt;/i&gt;');
assertConverts('<b>mismatched/unknown</bunknown>', '&lt;b&gt;mismatched/unknown&lt;/bunknown&gt;');
assertEscapes('<b>mismatched/unknown</bunknown>', '&lt;b&gt;mismatched/unknown&lt;/bunknown&gt;');

View File

@ -317,7 +317,6 @@
<dep package="gobject-introspection"/> <dep package="gobject-introspection"/>
<dep package="mutter"/> <dep package="mutter"/>
<dep package="gjs"/> <dep package="gjs"/>
<dep package="caribou"/>
<dep package="dconf"/> <dep package="dconf"/>
<dep package="gconf"/> <dep package="gconf"/>
<dep package="glib"/> <dep package="glib"/>
@ -411,7 +410,7 @@
</dependencies> </dependencies>
</tarball> </tarball>
<autotools id="caribou" autogenargs="--enable-gtk3-im"> <autotools id="caribou">
<branch repo="git.gnome.org" module="caribou"/> <branch repo="git.gnome.org" module="caribou"/>
</autotools> </autotools>