diff --git a/data/Makefile.am b/data/Makefile.am
index 06827d0b3..912ad3dbe 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -16,8 +16,6 @@ imagesdir = $(pkgdatadir)/images
dist_images_DATA = \
add-workspace.svg \
app-well-glow.png \
- back.svg \
- close.svg \
close-black.svg \
info.svg \
magnifier.svg \
@@ -26,11 +24,14 @@ dist_images_DATA = \
themedir = $(pkgdatadir)/theme
dist_theme_DATA = \
theme/gnome-shell.css \
+ theme/close.svg \
theme/scroll-button-down.png \
theme/scroll-button-down-hover.png \
theme/scroll-button-up.png \
theme/scroll-button-up-hover.png \
- theme/scroll-vhandle.png
+ theme/scroll-vhandle.png \
+ theme/section-back.svg \
+ theme/section-more.svg
schemadir = @GCONF_SCHEMA_FILE_DIR@
schema_DATA = gnome-shell.schemas
diff --git a/data/close.svg b/data/theme/close.svg
similarity index 100%
rename from data/close.svg
rename to data/theme/close.svg
diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css
index dfe8dc7cf..b04cb79a7 100644
--- a/data/theme/gnome-shell.css
+++ b/data/theme/gnome-shell.css
@@ -19,7 +19,6 @@
StScrollBar
{
- background-color: #354761;
padding: 0px;
}
@@ -61,6 +60,14 @@ StScrollBar StButton#vhandle:hover
border-image: url("scroll-vhandle.png") 5;
}
+StTooltip {
+ border: 1px solid rgba(79,111,173,0.9);
+ border-radius: 5px;
+ padding: 4px;
+ background-color: rgba(79,111,173,0.9);
+ color: #ffffff;
+}
+
/* Panel */
.panel-button {
@@ -74,6 +81,154 @@ StScrollBar StButton#vhandle:hover
background-color: #314a6c;
}
+/* Dash */
+
+#dash {
+ color: #5f5f5f;
+ background-color: rgba(0,0,0,0.75);
+ padding: 0px 14px;
+}
+
+#dashSections {
+ spacing: 12px;
+}
+
+.dash-search-section-header {
+ padding: 6px 0px;
+ spacing: 4px;
+ font-size: 12px;
+ color: #bbbbbb;
+}
+
+.dash-search-section-title, dash-search-section-count {
+ font-weight: bold;
+}
+
+#searchEntry {
+ padding: 4px;
+ border-bottom: 1px solid #262626;
+}
+
+#searchEntry:active {
+ background-color: #c4c4c4;
+}
+
+.dash-section {
+ spacing: 8px;
+}
+
+.section-header {
+ border: 1px solid #262626;
+ -shell-gradient-top: #161616;
+ -shell-gradient-bottom: #000000;
+ font-weight: bold;
+ font-size: 12px;
+}
+
+.section-header-inner {
+ border: 1px solid #000000;
+ padding: 0px 4px;
+ spacing: 4px;
+}
+
+.section-text-content {
+ padding: 4px 0px;
+}
+
+.section-header-back {
+ padding: 0px 4px 0px 0px;
+ border-right: 1px solid #262626;
+}
+
+.section-header-back-image {
+ background-image: url("section-back.svg");
+ width: 12px;
+ height: 16px;
+}
+
+.section-count {
+}
+
+.dash-section-content {
+ font-size: 14px;
+ color: #ffffff;
+ spacing: 8px;
+}
+
+.more-link {
+}
+
+.more-link-expander {
+ background-image: url("section-more.svg");
+ width: 9px;
+ height: 9px;
+}
+
+.dash-pane {
+ background-color: rgba(0,0,0,0.95);
+ border: 1px solid #262626;
+ padding: 4px;
+ spacing: 4px;
+}
+
+.dash-pane-close {
+ background-image: url("close.svg");
+ width: 16px;
+ height: 16px;
+}
+
+/* GenericDisplay */
+
+.generic-display-container {
+ spacing: 4px;
+}
+
+.generic-display-item {
+ height: 50px;
+ border-radius: 4px;
+ color: #ffffff;
+ font-size: 14px;
+ spacing: 4px;
+}
+
+.generic-display-item:selected {
+ background-color: rgba(79,111,173,0.66);
+}
+
+.generic-display-item-text {
+ spacing: 4px;
+}
+
+.generic-display-item-description {
+ font-size: 12px;
+ color: #bababa;
+}
+
+.generic-display-details {
+ font-size: 14px;
+ color: #ffffff;
+}
+
+.generic-display-details-name {
+ font-weight: bold;
+}
+
+/* AppIcon */
+
+.app-icon-label {
+ font-size: 12px;
+}
+
+/* Places */
+
+.places-actions {
+ spacing: 4px;
+}
+
+#placesDevices {
+ padding-top: 4px;
+}
+
/* LookingGlass */
#LookingGlassDialog
@@ -203,3 +358,10 @@ StScrollBar StButton#vhandle:hover
width: 1px;
background: rgba(255,255,255,0.33);
}
+
+/* Status Menu */
+#StatusMenu {
+ spacing: 4px;
+ font: 16px sans-serif;
+ color: white;
+}
diff --git a/data/back.svg b/data/theme/section-back.svg
similarity index 100%
rename from data/back.svg
rename to data/theme/section-back.svg
diff --git a/data/theme/section-more.svg b/data/theme/section-more.svg
new file mode 100755
index 000000000..74f579d63
--- /dev/null
+++ b/data/theme/section-more.svg
@@ -0,0 +1,87 @@
+
+
+
+
diff --git a/js/misc/docInfo.js b/js/misc/docInfo.js
index 021dce412..8123e281b 100644
--- a/js/misc/docInfo.js
+++ b/js/misc/docInfo.js
@@ -36,8 +36,8 @@ DocInfo.prototype = {
// shorter in terms of lines of code, we are not doing so
// because that would duplicate the work of retrieving the
// mime type.
-
- let appInfo = Gio.app_info_get_default_for_type(this.mimeType, true);
+ let needsUri = Gio.file_new_for_uri(this.uri).get_path() == null;
+ let appInfo = Gio.app_info_get_default_for_type(this.mimeType, needsUri);
if (appInfo != null) {
appInfo.launch_uris([this.uri], Main.createAppLaunchContext());
diff --git a/js/ui/Makefile.am b/js/ui/Makefile.am
index c5824a4ac..f303aa685 100644
--- a/js/ui/Makefile.am
+++ b/js/ui/Makefile.am
@@ -20,10 +20,11 @@ dist_jsui_DATA = \
messageTray.js \
overview.js \
panel.js \
- places.js \
+ placeDisplay.js \
runDialog.js \
shellDBus.js \
sidebar.js \
+ statusMenu.js \
tweener.js \
widget.js \
widgetBox.js \
diff --git a/js/ui/altTab.js b/js/ui/altTab.js
index da4c99641..dd7726631 100644
--- a/js/ui/altTab.js
+++ b/js/ui/altTab.js
@@ -724,7 +724,19 @@ ThumbnailList.prototype = {
_init : function(windows) {
SwitcherList.prototype._init.call(this);
+ let activeWorkspace = global.screen.get_active_workspace();
+
+ // We fake the value of "separatorAdded" when the app has no window
+ // on the current workspace, to avoid displaying a useless separator in
+ // that case.
+ let separatorAdded = windows.length == 0 || windows[0].get_workspace() != activeWorkspace;
+
for (let i = 0; i < windows.length; i++) {
+ if (!separatorAdded && windows[i].get_workspace() != activeWorkspace) {
+ this.addSeparator();
+ separatorAdded = true;
+ }
+
let mutterWindow = windows[i].get_compositor_private();
let windowTexture = mutterWindow.get_texture ();
let [width, height] = windowTexture.get_size();
@@ -739,11 +751,14 @@ ThumbnailList.prototype = {
height: height * scale });
box.add_actor(clone);
- let name = new St.Label({ text: windows[i].get_title() });
- // St.Label doesn't support text-align so use a Bin
- let bin = new St.Bin({ x_align: St.Align.MIDDLE });
- bin.add_actor(name);
- box.add_actor(bin);
+ let title = windows[i].get_title();
+ if (title) {
+ let name = new St.Label({ text: title });
+ // St.Label doesn't support text-align so use a Bin
+ let bin = new St.Bin({ x_align: St.Align.MIDDLE });
+ bin.add_actor(name);
+ box.add_actor(bin);
+ }
this.addItem(box);
}
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
index db2b507e3..c88191016 100644
--- a/js/ui/appDisplay.js
+++ b/js/ui/appDisplay.js
@@ -166,15 +166,15 @@ Signals.addSignalMethods(MenuItem.prototype);
* showPrefs - a boolean indicating if this AppDisplay should contain preference
* applets, rather than applications
*/
-function AppDisplay(showPrefs) {
- this._init(showPrefs);
+function AppDisplay(showPrefs, flags) {
+ this._init(showPrefs, flags);
}
AppDisplay.prototype = {
__proto__: GenericDisplay.GenericDisplay.prototype,
- _init : function(showPrefs) {
- GenericDisplay.GenericDisplay.prototype._init.call(this);
+ _init : function(showPrefs, flags) {
+ GenericDisplay.GenericDisplay.prototype._init.call(this, flags);
this._showPrefs = showPrefs;
@@ -190,156 +190,10 @@ AppDisplay.prototype = {
this._appsStale = true;
this._redisplay(GenericDisplay.RedisplayFlags.NONE);
}));
-
- this._focusInMenus = true;
- this._activeMenuIndex = -1;
- this._activeMenu = null;
- this._activeMenuApps = null;
- this._menuDisplay = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
- spacing: MENU_SPACING
- });
-
- this.connect('expanded', Lang.bind(this, function (self) {
- this._filterReset();
- }));
- this._filterReset();
- },
-
- moveRight: function() {
- if (this._expanded && this._focusInMenu) {
- this._focusInMenu = false;
- this._activeMenu.setState(MENU_ENTERED);
- this.selectFirstItem();
- }
- },
-
- moveLeft: function() {
- if (this._expanded && !this._focusInMenu) {
- this._activeMenu.setState(MENU_SELECTED);
- this.unsetSelected();
- this._focusInMenu = true;
- }
- },
-
- // Override genericDisplay.js
- getNavigationArea: function() {
- return this._menuDisplay;
- },
-
- selectUp: function() {
- if (!(this._expanded && this._focusInMenu))
- return GenericDisplay.GenericDisplay.prototype.selectUp.call(this);
- this._selectMenuIndex(this._activeMenuIndex - 1);
- return true;
- },
-
- selectDown: function() {
- if (!(this._expanded && this._focusInMenu))
- return GenericDisplay.GenericDisplay.prototype.selectDown.call(this);
- this._selectMenuIndex(this._activeMenuIndex+1);
- return true;
- },
-
- setSearch: function(text) {
- let lowertext = text.toLowerCase();
- if (lowertext == this._search)
- return;
-
- // We prepare menu matches up-front, so that we don't
- // need to go over all menu items for each application
- // and then get all applications for a matching menu
- // to see if a particular application passed to
- // _isInfoMatching() is a match.
- let terms = lowertext.split(/\s+/);
- this._menuSearchAppMatches = {};
- for (let i = 0; i < terms.length; i++) {
- let term = terms[i];
- this._menuSearchAppMatches[term] = {};
- for (let j = 0; j < this._menus.length; j++) {
- let menuItem = this._menus[j];
- // Match only on the beginning of the words in category names,
- // because otherwise it introduces unnecessary noise in the results.
- if (menuItem.name.toLowerCase().indexOf(term) == 0 ||
- menuItem.name.toLowerCase().indexOf(" " + term) > 0) {
- let menuApps = this._appSystem.get_applications_for_menu(menuItem.id);
- for (let k = 0; k < menuApps.length; k++) {
- let menuApp = menuApps[k];
- this._menuSearchAppMatches[term][menuApp.get_id()] = true;
- }
- }
- }
- }
-
- GenericDisplay.GenericDisplay.prototype.setSearch.call(this, text);
- },
-
- // Protected overrides
-
- _filterActive: function() {
- // We always have a filter now since a menu must be selected
- return true;
- },
-
- _filterReset: function() {
- GenericDisplay.GenericDisplay.prototype._filterReset.call(this);
- this._selectMenuIndex(0);
},
//// Private ////
- _emitStateChange: function() {
- this.emit('state-changed');
- },
-
- _selectMenuIndex: function(index) {
- if (index < 0 || index >= this._menus.length)
- return;
- this._menuDisplays[index].setState(MENU_SELECTED);
- },
-
- _getMostUsed: function() {
- let context = "";
- let usage = Shell.AppUsage.get_default();
- return usage.get_most_used(context, 30);
- },
-
- _addMenuItem: function(name, id, index) {
- let display = new MenuItem(name, id);
- this._menuDisplays.push(display);
- display.connect('state-changed', Lang.bind(this, function (display) {
- let activated = display.getState() != MENU_UNSELECTED;
- if (!activated && display == this._activeMenu) {
- this._activeMenuIndex = -1;
- this._activeMenu = null;
- } else if (activated) {
- if (display != this._activeMenu && this._activeMenu != null)
- this._activeMenu.setState(MENU_UNSELECTED);
- this._activeMenuIndex = index;
- this._activeMenu = display;
- if (id == null) {
- this._activeMenuApps = this._getMostUsed();
- } else {
- this._activeMenuApps = this._appSystem.get_applications_for_menu(id);
- }
- }
- this._redisplay(GenericDisplay.RedisplayFlags.FULL);
- }));
- this._menuDisplay.append(display.actor, 0);
- },
-
- _redisplayMenus: function() {
- this._menuDisplay.remove_all();
- this._addMenuItem(_("Frequent"), null, 'gtk-select-all');
- // Adding an empty box here results in double spacing between
- // "Frequent" and the other items.
- let separator_actor = new Big.Box();
- this._menuDisplay.append(separator_actor, 0);
- for (let i = 0; i < this._menus.length; i++) {
- let menu = this._menus[i];
- this._addMenuItem(menu.name, menu.id, i+1);
- }
- },
-
_addApp: function(appInfo) {
let appId = appInfo.get_id();
this._allItems[appId] = appInfo;
@@ -363,33 +217,33 @@ AppDisplay.prototype = {
}
} else {
// Loop over the toplevel menu items, load the set of desktop file ids
- // associated with each one, skipping empty menus
+ // associated with each one.
let allMenus = this._appSystem.get_menus();
- this._menus = [];
for (let i = 0; i < allMenus.length; i++) {
let menu = allMenus[i];
let menuApps = this._appSystem.get_applications_for_menu(menu.id);
- let hasVisibleApps = menuApps.some(function (app) { return !app.get_is_nodisplay(); });
- if (!hasVisibleApps) {
- continue;
- }
- this._menus.push(menu);
+
for (let j = 0; j < menuApps.length; j++) {
let app = menuApps[j];
this._addApp(app);
}
}
- this._redisplayMenus();
}
this._appsStale = false;
return false;
},
- // Stub this out; the app display always has a category selected
_setDefaultList : function() {
- this._matchedItems = {};
+ this._matchedItems = this._allItems;
this._matchedItemKeys = [];
+ for (let itemId in this._matchedItems) {
+ let app = this._allItems[itemId];
+ if (app.get_is_nodisplay())
+ continue;
+ this._matchedItemKeys.push(itemId);
+ }
+ this._matchedItemKeys.sort(Lang.bind(this, this._compareItems));
},
// Compares items associated with the item ids based on the alphabetical order
@@ -409,25 +263,7 @@ AppDisplay.prototype = {
// Don't show nodisplay items here
if (itemInfo.get_is_nodisplay())
return false;
- // Search takes precedence; not typically useful to search within a
- // menu
- if (this._activeMenu == null || search != "")
- return this._isInfoMatchingSearch(itemInfo, search);
- else
- return this._isInfoMatchingMenu(itemInfo);
- },
- _isInfoMatchingMenu: function(itemInfo) {
- let id = itemInfo.get_id();
- for (let i = 0; i < this._activeMenuApps.length; i++) {
- let activeApp = this._activeMenuApps[i];
- if (activeApp.get_id() == id)
- return true;
- }
- return false;
- },
-
- _isInfoMatchingSearch: function(itemInfo, search) {
if (search == null || search == '')
return true;
@@ -455,13 +291,6 @@ AppDisplay.prototype = {
return true;
}
- if (this._menuSearchAppMatches[search]) {
- if (this._menuSearchAppMatches[search].hasOwnProperty(itemInfo.get_id()))
- return true;
- } else {
- log("Missing an entry for search term " + search + " in this._menuSearchAppMatches");
- }
-
return false;
},
diff --git a/js/ui/appIcon.js b/js/ui/appIcon.js
index b2cc8af68..571e05097 100644
--- a/js/ui/appIcon.js
+++ b/js/ui/appIcon.js
@@ -8,6 +8,7 @@ const Mainloop = imports.mainloop;
const Pango = imports.gi.Pango;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
+const St = imports.gi.St;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
@@ -99,11 +100,9 @@ AppIcon.prototype = {
nameBox.connect('allocate', Lang.bind(this, this._nameBoxAllocate));
this._nameBox = nameBox;
- this._name = new Clutter.Text({ color: GenericDisplay.ITEM_DISPLAY_NAME_COLOR,
- font_name: "Sans 12px",
- line_alignment: Pango.Alignment.CENTER,
- ellipsize: Pango.EllipsizeMode.END,
- text: this.app.get_name() });
+ this._name = new St.Label({ style_class: "app-icon-label",
+ text: this.app.get_name() });
+ this._name.clutter_text.line_alignment = Pango.Alignment.CENTER;
nameBox.add_actor(this._name);
if (this._showGlow) {
this._glowBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL });
diff --git a/js/ui/dash.js b/js/ui/dash.js
index 2f367753a..3398fce9e 100644
--- a/js/ui/dash.js
+++ b/js/ui/dash.js
@@ -8,22 +8,19 @@ const Pango = imports.gi.Pango;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const Lang = imports.lang;
+const St = imports.gi.St;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const AppDisplay = imports.ui.appDisplay;
const DocDisplay = imports.ui.docDisplay;
-const Places = imports.ui.places;
+const PlaceDisplay = imports.ui.placeDisplay;
const GenericDisplay = imports.ui.genericDisplay;
const Button = imports.ui.button;
const Main = imports.ui.main;
const DEFAULT_PADDING = 4;
const DEFAULT_SPACING = 4;
-const DASH_SECTION_PADDING = 6;
-const DASH_SECTION_SPACING = 40;
-const DASH_CORNER_RADIUS = 5;
-const DASH_PADDING_SIDE = 14;
const BACKGROUND_COLOR = new Clutter.Color();
BACKGROUND_COLOR.from_pixel(0x000000c0);
@@ -43,42 +40,22 @@ SEARCH_TEXT_COLOR.from_pixel(0x333333ff);
const SEARCH_CURSOR_COLOR = BRIGHT_TEXT_COLOR;
const HIGHLIGHTED_SEARCH_CURSOR_COLOR = SEARCH_TEXT_COLOR;
-const HIGHLIGHTED_SEARCH_BACKGROUND_COLOR = new Clutter.Color();
-HIGHLIGHTED_SEARCH_BACKGROUND_COLOR.from_pixel(0xc4c4c4ff);
-
const SEARCH_BORDER_BOTTOM_COLOR = new Clutter.Color();
SEARCH_BORDER_BOTTOM_COLOR.from_pixel(0x191919ff);
-const SECTION_BORDER_COLOR = new Clutter.Color();
-SECTION_BORDER_COLOR.from_pixel(0x262626ff);
-const SECTION_BORDER = 1;
-const SECTION_INNER_BORDER_COLOR = new Clutter.Color();
-SECTION_INNER_BORDER_COLOR.from_pixel(0x000000ff);
-const SECTION_BACKGROUND_TOP_COLOR = new Clutter.Color();
-SECTION_BACKGROUND_TOP_COLOR.from_pixel(0x161616ff);
-const SECTION_BACKGROUND_BOTTOM_COLOR = new Clutter.Color();
-SECTION_BACKGROUND_BOTTOM_COLOR.from_pixel(0x000000ff);
-const SECTION_INNER_SPACING = 8;
-
const BROWSE_ACTIVATED_BG = new Clutter.Color();
BROWSE_ACTIVATED_BG.from_pixel(0x303030f0);
-const PANE_BORDER_COLOR = new Clutter.Color();
-PANE_BORDER_COLOR.from_pixel(0x101d3cfa);
-const PANE_BORDER_WIDTH = 2;
-
-const PANE_BACKGROUND_COLOR = new Clutter.Color();
-PANE_BACKGROUND_COLOR.from_pixel(0x000000f4);
-
const APPS = "apps";
const PREFS = "prefs";
const DOCS = "docs";
+const PLACES = "places";
/*
* Returns the index in an array of a given length that is obtained
* if the provided index is incremented by an increment and the array
* is wrapped in if necessary.
- *
+ *
* index: prior index, expects 0 <= index < length
* increment: the change in index, expects abs(increment) <= length
* length: the length of the array
@@ -87,14 +64,15 @@ function _getIndexWrapped(index, increment, length) {
return (index + increment + length) % length;
}
-function _createDisplay(displayType) {
+function _createDisplay(displayType, flags) {
if (displayType == APPS)
- return new AppDisplay.AppDisplay();
+ return new AppDisplay.AppDisplay(false, flags);
else if (displayType == PREFS)
- return new AppDisplay.AppDisplay(true);
+ return new AppDisplay.AppDisplay(true, flags);
else if (displayType == DOCS)
- return new DocDisplay.DocDisplay();
-
+ return new DocDisplay.DocDisplay(flags);
+ else if (displayType == PLACES)
+ return new PlaceDisplay.PlaceDisplay(flags);
return null;
}
@@ -106,36 +84,27 @@ Pane.prototype = {
_init: function () {
this._open = false;
- this.actor = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
- background_color: PANE_BACKGROUND_COLOR,
- border: PANE_BORDER_WIDTH,
- border_color: PANE_BORDER_COLOR,
- padding: DEFAULT_PADDING,
- reactive: true });
+ this.actor = new St.BoxLayout({ style_class: "dash-pane",
+ vertical: true,
+ reactive: true });
this.actor.connect('button-press-event', Lang.bind(this, function (a, e) {
// Eat button press events so they don't go through and close the pane
return true;
}));
- let chromeTop = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
- spacing: 6 });
+ let chromeTop = new St.BoxLayout();
- let closeIconUri = "file://" + global.imagedir + "close.svg";
- let closeIcon = Shell.TextureCache.get_default().load_uri_sync(Shell.TextureCachePolicy.FOREVER,
- closeIconUri,
- 16,
- 16);
- closeIcon.reactive = true;
- closeIcon.connect('button-press-event', Lang.bind(this, function (b, e) {
+ let closeIcon = new St.Button({ style_class: "dash-pane-close" });
+ closeIcon.connect('clicked', Lang.bind(this, function (b, e) {
this.close();
- return true;
}));
- chromeTop.append(closeIcon, Big.BoxPackFlags.END);
- this.actor.append(chromeTop, Big.BoxPackFlags.NONE);
+ let dummy = new St.Bin();
+ chromeTop.add(dummy, { expand: true });
+ chromeTop.add(closeIcon, { x_align: St.Align.END });
+ this.actor.add(chromeTop);
- this.content = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
- spacing: DEFAULT_PADDING });
- this.actor.append(this.content, Big.BoxPackFlags.EXPAND);
+ this.content = new St.BoxLayout({ vertical: true });
+ this.actor.add(this.content, { expand: true });
// Hidden by default
this.actor.hide();
@@ -173,32 +142,20 @@ Pane.prototype = {
}
Signals.addSignalMethods(Pane.prototype);
-function ResultArea(displayType, enableNavigation) {
- this._init(displayType, enableNavigation);
+function ResultArea(displayType, flags) {
+ this._init(displayType, flags);
}
ResultArea.prototype = {
- _init : function(displayType, enableNavigation) {
+ _init : function(displayType, flags) {
this.actor = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL });
this.resultsContainer = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
spacing: DEFAULT_PADDING
});
this.actor.append(this.resultsContainer, Big.BoxPackFlags.EXPAND);
- this.navContainer = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL });
- this.resultsContainer.append(this.navContainer, Big.BoxPackFlags.NONE);
-
- this.display = _createDisplay(displayType);
-
- this.navArea = this.display.getNavigationArea();
- if (enableNavigation && this.navArea)
- this.navContainer.append(this.navArea, Big.BoxPackFlags.EXPAND);
+ this.display = _createDisplay(displayType, flags);
this.resultsContainer.append(this.display.actor, Big.BoxPackFlags.EXPAND);
-
- this.controlBox = new Big.Box({ x_align: Big.BoxAlignment.CENTER });
- this.controlBox.append(this.display.displayControl, Big.BoxPackFlags.NONE);
- this.actor.append(this.controlBox, Big.BoxPackFlags.NONE);
-
this.display.load();
}
}
@@ -223,7 +180,7 @@ function createPaneForDetails(dash, display) {
if (index >= 0) {
detailPane.destroyContent();
let details = display.createDetailsForIndex(index);
- detailPane.content.append(details, Big.BoxPackFlags.EXPAND);
+ detailPane.content.add(details, { expand: true });
detailPane.open();
} else {
detailPane.close();
@@ -246,12 +203,12 @@ ResultPane.prototype = {
// Create a display of displayType and pack it into this pane's
// content area. Return the display.
- packResults: function(displayType, enableNavigation) {
- let resultArea = new ResultArea(displayType, enableNavigation);
+ packResults: function(displayType) {
+ let resultArea = new ResultArea(displayType);
createPaneForDetails(this._dash, resultArea.display);
- this.content.append(resultArea.actor, Big.BoxPackFlags.EXPAND);
+ this.content.add(resultArea.actor, { expand: true });
this.connect('open-state-changed', Lang.bind(this, function(pane, isOpen) {
resultArea.display.resetState();
}));
@@ -265,14 +222,11 @@ function SearchEntry() {
SearchEntry.prototype = {
_init : function() {
- this.actor = new Big.Box({ padding: DEFAULT_PADDING,
- border_bottom: SECTION_BORDER,
- border_color: SEARCH_BORDER_BOTTOM_COLOR,
- corner_radius: DASH_CORNER_RADIUS,
- reactive: true });
+ this.actor = new St.BoxLayout({ name: "searchEntry",
+ reactive: true });
let box = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
y_align: Big.BoxAlignment.CENTER });
- this.actor.append(box, Big.BoxPackFlags.EXPAND);
+ this.actor.add(box, { expand: true });
this.actor.connect('button-press-event', Lang.bind(this, function () {
this._resetTextState(true);
return false;
@@ -332,7 +286,7 @@ SearchEntry.prototype = {
else
this.entry.text = '';
- // Return true to stop the signal emission, so that this.actor doesn't get
+ // Return true to stop the signal emission, so that this.actor doesn't get
// the button-press-event and re-highlight itself.
return true;
}));
@@ -355,18 +309,18 @@ SearchEntry.prototype = {
_resetTextState: function (searchEntryClicked) {
let text = this.getText();
this._iconBox.remove_all();
- // We highlight the search box if the user starts typing in it
+ // We highlight the search box if the user starts typing in it
// or just clicks in it to indicate that the search is active.
if (text != '' || searchEntryClicked) {
if (!searchEntryClicked)
this._defaultText.hide();
this._iconBox.append(this._closeIcon, Big.BoxPackFlags.NONE);
- this.actor.background_color = HIGHLIGHTED_SEARCH_BACKGROUND_COLOR;
+ this.actor.set_style_pseudo_class('active');
this.entry.cursor_color = HIGHLIGHTED_SEARCH_CURSOR_COLOR;
} else {
this._defaultText.show();
this._iconBox.append(this._magnifierIcon, Big.BoxPackFlags.NONE);
- this.actor.background_color = BACKGROUND_COLOR;
+ this.actor.set_style_pseudo_class(null);
this.entry.cursor_color = SEARCH_CURSOR_COLOR;
}
},
@@ -385,20 +339,12 @@ function MoreLink() {
MoreLink.prototype = {
_init : function () {
- this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
- padding_right: DEFAULT_PADDING,
- padding_left: DEFAULT_PADDING,
- reactive: true,
- x_align: Big.BoxAlignment.CENTER,
- y_align: Big.BoxAlignment.CENTER,
- border_left: SECTION_BORDER,
- border_color: SECTION_BORDER_COLOR });
+ this.actor = new St.BoxLayout({ style_class: "more-link",
+ reactive: true });
this.pane = null;
- let text = new Clutter.Text({ font_name: "Sans 12px",
- color: BRIGHT_TEXT_COLOR,
- text: _("More") });
- this.actor.append(text, Big.BoxPackFlags.NONE);
+ let expander = new St.Bin({ style_class: "more-link-expander" });
+ this.actor.add(expander, { expand: true, y_fill: false });
this.actor.connect('button-press-event', Lang.bind(this, function (b, e) {
if (this.pane == null) {
@@ -425,21 +371,9 @@ function BackLink() {
BackLink.prototype = {
_init : function () {
- this.actor = new Shell.ButtonBox({ orientation: Big.BoxOrientation.HORIZONTAL,
- padding_right: DEFAULT_PADDING,
- padding_left: DEFAULT_PADDING,
- reactive: true,
- x_align: Big.BoxAlignment.CENTER,
- y_align: Big.BoxAlignment.CENTER,
- border_right: SECTION_BORDER,
- border_color: SECTION_BORDER_COLOR });
-
- let backIconUri = "file://" + global.imagedir + "back.svg";
- let backIcon = Shell.TextureCache.get_default().load_uri_sync(Shell.TextureCachePolicy.FOREVER,
- backIconUri,
- 12,
- 16);
- this.actor.append(backIcon, Big.BoxPackFlags.NONE);
+ this.actor = new St.Button({ style_class: "section-header-back",
+ reactive: true });
+ this.actor.set_child(new St.Bin({ style_class: "section-header-back-image" }));
}
}
@@ -449,52 +383,72 @@ function SectionHeader(title, suppressBrowse) {
SectionHeader.prototype = {
_init : function (title, suppressBrowse) {
- this.actor = new Big.Box({ border: SECTION_BORDER,
- border_color: SECTION_BORDER_COLOR });
- this._innerBox = new Big.Box({ border: SECTION_BORDER,
- border_color: SECTION_INNER_BORDER_COLOR,
- padding_left: DEFAULT_PADDING,
- padding_right: DEFAULT_PADDING,
- orientation: Big.BoxOrientation.HORIZONTAL,
- spacing: DEFAULT_SPACING });
- this.actor.append(this._innerBox, Big.BoxPackFlags.EXPAND);
- let backgroundGradient = Shell.create_vertical_gradient(SECTION_BACKGROUND_TOP_COLOR,
- SECTION_BACKGROUND_BOTTOM_COLOR);
- this._innerBox.add_actor(backgroundGradient);
- this._innerBox.connect('notify::allocation', Lang.bind(this, function (actor) {
- let [width, height] = actor.get_size();
- backgroundGradient.set_size(width, height);
+ this.actor = new St.Bin({ style_class: "section-header",
+ x_align: St.Align.START,
+ x_fill: true,
+ y_fill: true });
+ this._innerBox = new St.BoxLayout({ style_class: "section-header-inner" });
+ this.actor.set_child(this._innerBox);
+
+ this._backgroundGradient = null;
+ this.actor.connect('style-changed', Lang.bind(this, this._onStyleChanged));
+ this.actor.connect('notify::allocation', Lang.bind(this, function (actor) {
+ if (!this._backgroundGradient)
+ return;
+ this._onStyleChanged();
}));
this.backLink = new BackLink();
- this._innerBox.append(this.backLink.actor, Big.BoxPackFlags.NONE);
+ this._innerBox.add(this.backLink.actor);
this.backLink.actor.hide();
-
- this.backLink.actor.connect('activate', Lang.bind(this, function (actor) {
- this.emit('back-link-activated');
+ this.backLink.actor.connect('clicked', Lang.bind(this, function (actor) {
+ this.emit('back-link-activated');
}));
- let textBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
- padding_top: DEFAULT_PADDING,
- padding_bottom: DEFAULT_PADDING });
- this.text = new Clutter.Text({ color: TEXT_COLOR,
- font_name: "Sans Bold 12px",
- text: title });
- textBox.append(this.text, Big.BoxPackFlags.NONE);
+ let textBox = new St.BoxLayout({ style_class: "section-text-content" });
+ this.text = new St.Label({ style_class: "section-title",
+ text: title });
+ textBox.add(this.text, { x_align: St.Align.START });
- this.countText = new Clutter.Text({ color: TEXT_COLOR,
- font_name: 'Sans Bold 14px' });
- textBox.append(this.countText, Big.BoxPackFlags.END);
+ this.countText = new St.Label({ style_class: "section-count" });
+ textBox.add(this.countText, { expand: true, x_fill: false, x_align: St.Align.END });
this.countText.hide();
- this._innerBox.append(textBox, Big.BoxPackFlags.EXPAND);
+ this._innerBox.add(textBox, { expand: true });
if (!suppressBrowse) {
this.moreLink = new MoreLink();
- this._innerBox.append(this.moreLink.actor, Big.BoxPackFlags.END);
+ this._innerBox.add(this.moreLink.actor, { x_align: St.Align.END });
}
},
+ _onStyleChanged: function () {
+ if (this._backgroundGradient) {
+ this._backgroundGradient.destroy();
+ }
+ // Manually implement the gradient
+ let themeNode = this.actor.get_theme_node();
+ let gradientTopColor = new Clutter.Color();
+ if (!themeNode.get_color("-shell-gradient-top", false, gradientTopColor))
+ return;
+ let gradientBottomColor = new Clutter.Color();
+ if (!themeNode.get_color("-shell-gradient-bottom", false, gradientBottomColor))
+ return;
+ this._backgroundGradient = Shell.create_vertical_gradient(gradientTopColor,
+ gradientBottomColor);
+ let box = this.actor.allocation;
+ let contentBox = new Clutter.ActorBox();
+ themeNode.get_content_box(box, contentBox);
+ let width = contentBox.x2 - contentBox.x1;
+ let height = contentBox.y2 - contentBox.y1;
+ this._backgroundGradient.set_size(width, height);
+ // This will set a fixed position, which puts us outside of the normal box layout
+ this._backgroundGradient.set_position(0, 0);
+
+ this._innerBox.add_actor(this._backgroundGradient);
+ this._backgroundGradient.lower_bottom();
+ },
+
setTitle : function(title) {
this.text.text = title;
},
@@ -531,41 +485,19 @@ function SearchSectionHeader(title, onClick) {
SearchSectionHeader.prototype = {
_init : function(title, onClick) {
- let box = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
- padding_top: DASH_SECTION_PADDING,
- padding_bottom: DASH_SECTION_PADDING,
- spacing: DEFAULT_SPACING });
- let titleText = new Clutter.Text({ color: BRIGHTER_TEXT_COLOR,
- font_name: 'Sans Bold 12px',
- text: title });
- this.tooltip = new Clutter.Text({ color: BRIGHTER_TEXT_COLOR,
- font_name: 'Sans 12px',
- text: _("(see all)") });
- this.countText = new Clutter.Text({ color: BRIGHTER_TEXT_COLOR,
- font_name: 'Sans Bold 14px' });
+ this.actor = new St.Button({ style_class: "dash-search-section-header",
+ x_fill: true,
+ y_fill: true });
+ let box = new St.BoxLayout();
+ this.actor.set_child(box);
+ let titleText = new St.Label({ style_class: "dash-search-section-title",
+ text: title });
+ this.countText = new St.Label({ style_class: "dash-search-section-count" });
- box.append(titleText, Big.BoxPackFlags.NONE);
- box.append(this.tooltip, Big.BoxPackFlags.NONE);
- box.append(this.countText, Big.BoxPackFlags.END);
+ box.add(titleText);
+ box.add(this.countText, { expand: true, x_fill: false, x_align: St.Align.END });
- this.tooltip.hide();
-
- let button = new Button.Button(box, PRELIGHT_COLOR, BACKGROUND_COLOR,
- TEXT_COLOR);
- button.actor.height = box.height;
- button.actor.padding_left = DEFAULT_PADDING;
- button.actor.padding_right = DEFAULT_PADDING;
-
- button.actor.connect('activate', onClick);
- button.actor.connect('notify::hover', Lang.bind(this, this._updateTooltip));
- this.actor = button.actor;
- },
-
- _updateTooltip : function(actor) {
- if (actor.hover)
- this.tooltip.show();
- else
- this.tooltip.hide();
+ this.actor.connect('clicked', onClick);
}
}
@@ -575,11 +507,13 @@ function Section(titleString, suppressBrowse) {
Section.prototype = {
_init: function(titleString, suppressBrowse) {
- this.actor = new Big.Box({ spacing: SECTION_INNER_SPACING });
+ this.actor = new St.BoxLayout({ style_class: 'dash-section',
+ vertical: true });
this.header = new SectionHeader(titleString, suppressBrowse);
- this.actor.append(this.header.actor, Big.BoxPackFlags.NONE);
- this.content = new Big.Box({spacing: SECTION_INNER_SPACING });
- this.actor.append(this.content, Big.BoxPackFlags.EXPAND);
+ this.actor.add(this.header.actor);
+ this.content = new St.BoxLayout({ style_class: 'dash-section-content',
+ vertical: true });
+ this.actor.add(this.content);
}
}
@@ -598,21 +532,18 @@ Dash.prototype = {
// of the Group actor ends up including the width of its hidden children, so we were getting a reactive object as
// wide as the details pane that was blocking the clicks to the workspaces underneath it even when the details pane
// was actually hidden.
- this.actor = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
- background_color: BACKGROUND_COLOR,
- corner_radius: DASH_CORNER_RADIUS,
- padding_left: DASH_PADDING_SIDE,
- padding_right: DASH_PADDING_SIDE,
- reactive: true });
+ this.actor = new St.BoxLayout({ name: "dash",
+ vertical: true,
+ reactive: true });
// Size for this one explicitly set from overlay.js
this.searchArea = new Big.Box({ y_align: Big.BoxAlignment.CENTER });
- this.sectionArea = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
- spacing: DASH_SECTION_SPACING });
+ this.sectionArea = new St.BoxLayout({ name: "dashSections",
+ vertical: true });
- this.actor.append(this.searchArea, Big.BoxPackFlags.NONE);
- this.actor.append(this.sectionArea, Big.BoxPackFlags.NONE);
+ this.actor.add(this.searchArea);
+ this.actor.add(this.sectionArea);
// The currently active popup display
this._activePane = null;
@@ -724,41 +655,41 @@ Dash.prototype = {
this._appsSection = new Section(_("APPLICATIONS"));
let appWell = new AppDisplay.AppWell();
- this._appsSection.content.append(appWell.actor, Big.BoxPackFlags.EXPAND);
+ this._appsSection.content.add(appWell.actor, { expand: true });
this._moreAppsPane = null;
this._appsSection.header.moreLink.connect('activated', Lang.bind(this, function (link) {
if (this._moreAppsPane == null) {
this._moreAppsPane = new ResultPane(this);
- this._moreAppsPane.packResults(APPS, true);
+ this._moreAppsPane.packResults(APPS);
this._addPane(this._moreAppsPane);
link.setPane(this._moreAppsPane);
}
}));
- this.sectionArea.append(this._appsSection.actor, Big.BoxPackFlags.NONE);
+ this.sectionArea.add(this._appsSection.actor);
/***** Places *****/
/* Translators: This is in the sense of locations for documents,
network locations, etc. */
this._placesSection = new Section(_("PLACES"), true);
- let placesDisplay = new Places.Places();
- this._placesSection.content.append(placesDisplay.actor, Big.BoxPackFlags.EXPAND);
- this.sectionArea.append(this._placesSection.actor, Big.BoxPackFlags.NONE);
+ let placesDisplay = new PlaceDisplay.DashPlaceDisplay();
+ this._placesSection.content.add(placesDisplay.actor, { expand: true });
+ this.sectionArea.add(this._placesSection.actor);
/***** Documents *****/
this._docsSection = new Section(_("RECENT DOCUMENTS"));
this._docDisplay = new DocDisplay.DashDocDisplay();
- this._docsSection.content.append(this._docDisplay.actor, Big.BoxPackFlags.EXPAND);
+ this._docsSection.content.add(this._docDisplay.actor, { expand: true });
this._moreDocsPane = null;
this._docsSection.header.moreLink.connect('activated', Lang.bind(this, function (link) {
if (this._moreDocsPane == null) {
this._moreDocsPane = new ResultPane(this);
- this._moreDocsPane.packResults(DOCS, true);
+ this._moreDocsPane.packResults(DOCS);
this._addPane(this._moreDocsPane);
link.setPane(this._moreDocsPane);
}
@@ -770,7 +701,7 @@ Dash.prototype = {
}));
this._docDisplay.emit('changed');
- this.sectionArea.append(this._docsSection.actor, Big.BoxPackFlags.EXPAND);
+ this.sectionArea.add(this._docsSection.actor, { expand: true });
/***** Search Results *****/
@@ -797,6 +728,11 @@ Dash.prototype = {
title: _("RECENT DOCUMENTS"),
header: null,
resultArea: null
+ },
+ { type: PLACES,
+ title: _("PLACES"),
+ header: null,
+ resultArea: null
}
];
@@ -807,14 +743,13 @@ Dash.prototype = {
function () {
this._showSingleSearchSection(section.type);
}));
- this._searchResultsSection.content.append(section.header.actor, Big.BoxPackFlags.NONE);
- section.resultArea = new ResultArea(section.type, false);
- section.resultArea.controlBox.hide();
- this._searchResultsSection.content.append(section.resultArea.actor, Big.BoxPackFlags.EXPAND);
+ this._searchResultsSection.content.add(section.header.actor);
+ section.resultArea = new ResultArea(section.type, GenericDisplay.GenericDisplayFlags.DISABLE_VSCROLLING);
+ this._searchResultsSection.content.add(section.resultArea.actor, { expand: true });
createPaneForDetails(this, section.resultArea.display);
}
- this.sectionArea.append(this._searchResultsSection.actor, Big.BoxPackFlags.EXPAND);
+ this.sectionArea.add(this._searchResultsSection.actor, { expand: true });
this._searchResultsSection.actor.hide();
},
@@ -859,6 +794,11 @@ Dash.prototype = {
}
}
+ // Here work around a bug that I never quite tracked down
+ // the root cause of; it appeared that the search results
+ // section was getting a 0 height allocation.
+ this._searchResultsSection.content.queue_relayout();
+
return false;
},
@@ -926,7 +866,6 @@ Dash.prototype = {
if (section.type == type) {
// This will be the only section shown.
section.resultArea.display.selectFirstItem();
- section.resultArea.controlBox.show();
let itemCount = section.resultArea.display.getMatchedItemsCount();
let itemCountText = itemCount + "";
section.header.actor.hide();
@@ -950,8 +889,6 @@ Dash.prototype = {
let section = this._searchSections[i];
if (section.type == this._searchResultsSingleShownSection) {
// This will no longer be the only section shown.
- section.resultArea.display.displayPage(0);
- section.resultArea.controlBox.hide();
let itemCount = section.resultArea.display.getMatchedItemsCount();
if (itemCount != 0) {
section.header.actor.show();
diff --git a/js/ui/docDisplay.js b/js/ui/docDisplay.js
index 9596b0b43..2b67f50ba 100644
--- a/js/ui/docDisplay.js
+++ b/js/ui/docDisplay.js
@@ -8,6 +8,7 @@ const Lang = imports.lang;
const Pango = imports.gi.Pango;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
+const St = imports.gi.St;
const Mainloop = imports.mainloop;
const DocInfo = imports.misc.docInfo;
@@ -111,19 +112,19 @@ DocDisplayItem.prototype = {
/* This class represents a display containing a collection of document items.
* The documents are sorted by how recently they were last visited.
*/
-function DocDisplay() {
- this._init();
+function DocDisplay(flags) {
+ this._init(flags);
}
DocDisplay.prototype = {
__proto__: GenericDisplay.GenericDisplay.prototype,
- _init : function() {
- GenericDisplay.GenericDisplay.prototype._init.call(this);
+ _init : function(flags) {
+ GenericDisplay.GenericDisplay.prototype._init.call(this, flags);
// We keep a single timeout callback for updating last visited times
// for all the items in the display. This avoids creating individual
// callbacks for each item in the display. So proper time updates
- // for individual items and item details depend on the item being
+ // for individual items and item details depend on the item being
// associated with one of the displays.
this._updateTimeoutTargetTime = -1;
this._updateTimeoutId = 0;
@@ -278,10 +279,8 @@ DashDocDisplayItem.prototype = {
let iconBox = new Big.Box({ y_align: Big.BoxAlignment.CENTER });
iconBox.append(this._icon, Big.BoxPackFlags.NONE);
this.actor.append(iconBox, Big.BoxPackFlags.NONE);
- let name = new Clutter.Text({ font_name: "Sans 14px",
- color: GenericDisplay.ITEM_DISPLAY_NAME_COLOR,
- ellipsize: Pango.EllipsizeMode.END,
- text: docInfo.name });
+ let name = new St.Label({ style_class: "dash-recent-docs-item",
+ text: docInfo.name });
this.actor.append(name, Big.BoxPackFlags.EXPAND);
let draggable = DND.makeDraggable(this.actor);
diff --git a/js/ui/environment.js b/js/ui/environment.js
index 6d0bb4884..dbf816413 100644
--- a/js/ui/environment.js
+++ b/js/ui/environment.js
@@ -1,6 +1,7 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const St = imports.gi.St;
+const Gettext_gtk20 = imports.gettext.domain('gtk20');
const Tweener = imports.ui.tweener;
@@ -33,4 +34,9 @@ _patchContainerClass(St.Table);
function init() {
Tweener.init();
String.prototype.format = Format.format;
+
+ // Set the default direction for St widgets (this needs to be done before any use of St)
+ if (Gettext_gtk20.gettext("default:LTR") == "default:RTL") {
+ St.Widget.set_default_direction(St.TextDirection.RTL);
+ }
}
diff --git a/js/ui/genericDisplay.js b/js/ui/genericDisplay.js
index 4744669a2..d5c3e3f38 100644
--- a/js/ui/genericDisplay.js
+++ b/js/ui/genericDisplay.js
@@ -11,6 +11,7 @@ const Meta = imports.gi.Meta;
const Pango = imports.gi.Pango;
const Signals = imports.signals;
const Shell = imports.gi.Shell;
+const St = imports.gi.St;
const Button = imports.ui.button;
const DND = imports.ui.dnd;
@@ -18,18 +19,12 @@ const Link = imports.ui.link;
const Main = imports.ui.main;
const RedisplayFlags = { NONE: 0,
- RESET_CONTROLS: 1 << 0,
FULL: 1 << 1,
- SUBSEARCH: 1 << 2 };
+ SUBSEARCH: 1 << 2,
+ IMMEDIATE: 1 << 3 };
-const ITEM_DISPLAY_NAME_COLOR = new Clutter.Color();
-ITEM_DISPLAY_NAME_COLOR.from_pixel(0xffffffff);
const ITEM_DISPLAY_DESCRIPTION_COLOR = new Clutter.Color();
ITEM_DISPLAY_DESCRIPTION_COLOR.from_pixel(0xffffffbb);
-const ITEM_DISPLAY_BACKGROUND_COLOR = new Clutter.Color();
-ITEM_DISPLAY_BACKGROUND_COLOR.from_pixel(0x00000000);
-const ITEM_DISPLAY_SELECTED_BACKGROUND_COLOR = new Clutter.Color();
-ITEM_DISPLAY_SELECTED_BACKGROUND_COLOR.from_pixel(0x4f6fadaa);
const DISPLAY_CONTROL_SELECTED_COLOR = new Clutter.Color();
DISPLAY_CONTROL_SELECTED_COLOR.from_pixel(0x112288ff);
const PREVIEW_BOX_BACKGROUND_COLOR = new Clutter.Color();
@@ -37,10 +32,7 @@ PREVIEW_BOX_BACKGROUND_COLOR.from_pixel(0xADADADf0);
const DEFAULT_PADDING = 4;
-const ITEM_DISPLAY_HEIGHT = 50;
const ITEM_DISPLAY_ICON_SIZE = 48;
-const ITEM_DISPLAY_PADDING = 1;
-const ITEM_DISPLAY_PADDING_RIGHT = 2;
const DEFAULT_COLUMN_GAP = 6;
const PREVIEW_ICON_SIZE = 96;
@@ -63,12 +55,8 @@ function GenericDisplayItem() {
GenericDisplayItem.prototype = {
_init: function() {
- this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
- spacing: ITEM_DISPLAY_PADDING,
- reactive: true,
- background_color: ITEM_DISPLAY_BACKGROUND_COLOR,
- corner_radius: 4,
- height: ITEM_DISPLAY_HEIGHT });
+ this.actor = new St.BoxLayout({ style_class: "generic-display-item",
+ reactive: true });
this.actor._delegate = this;
this.actor.connect('button-release-event',
@@ -82,16 +70,12 @@ GenericDisplayItem.prototype = {
let draggable = DND.makeDraggable(this.actor);
draggable.connect('drag-begin', Lang.bind(this, this._onDragBegin));
- this._infoContent = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
- spacing: DEFAULT_PADDING });
- this.actor.append(this._infoContent, Big.BoxPackFlags.EXPAND);
+ this._iconBin = new St.Bin();
+ this.actor.add(this._iconBin);
- this._iconBox = new Big.Box();
- this._infoContent.append(this._iconBox, Big.BoxPackFlags.NONE);
-
- this._infoText = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
- spacing: DEFAULT_PADDING });
- this._infoContent.append(this._infoText, Big.BoxPackFlags.EXPAND);
+ this._infoText = new St.BoxLayout({ style_class: "generic-display-item-text",
+ vertical: true });
+ this.actor.add(this._infoText, { expand: true, y_fill: false });
let infoIconUri = "file://" + global.imagedir + "info.svg";
let infoIcon = Shell.TextureCache.get_default().load_uri_sync(Shell.TextureCachePolicy.FOREVER,
@@ -104,7 +88,7 @@ GenericDisplayItem.prototype = {
padding_left: DEFAULT_PADDING, padding_right: DEFAULT_PADDING,
y_align: Big.BoxAlignment.CENTER });
buttonBox.append(this._informationButton.actor, Big.BoxPackFlags.NONE);
- this.actor.append(buttonBox, Big.BoxPackFlags.END);
+ this.actor.add(buttonBox, { x_fill: false, x_align: St.Align.END });
// Connecting to the button-press-event for the information button ensures that the actor,
// which is a draggable actor, does not get the button-press-event and doesn't initiate
@@ -160,16 +144,8 @@ GenericDisplayItem.prototype = {
// Highlights the item by setting a different background color than the default
// if isSelected is true, removes the highlighting otherwise.
markSelected: function(isSelected) {
- let color;
- if (isSelected) {
- color = ITEM_DISPLAY_SELECTED_BACKGROUND_COLOR;
- this._informationButton.forceShow(true);
- }
- else {
- color = ITEM_DISPLAY_BACKGROUND_COLOR;
- this._informationButton.forceShow(false);
- }
- this.actor.background_color = color;
+ this.actor.set_style_pseudo_class(isSelected ? "selected" : null);
+ this._informationButton.forceShow(isSelected)
},
/*
@@ -185,19 +161,14 @@ GenericDisplayItem.prototype = {
spacing: PREVIEW_BOX_SPACING });
// Inner box with name and description
- let textDetails = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
- spacing: PREVIEW_BOX_SPACING });
- let detailsName = new Clutter.Text({ color: ITEM_DISPLAY_NAME_COLOR,
- font_name: "Sans bold 14px",
- line_wrap: true,
- text: this._name.text });
- textDetails.append(detailsName, Big.BoxPackFlags.NONE);
+ let textDetails = new St.BoxLayout({ style_class: 'generic-display-details',
+ vertical: true });
+ let detailsName = new St.Label({ style_class: 'generic-display-details-name',
+ text: this._name.text });
+ textDetails.add(detailsName);
- let detailsDescription = new Clutter.Text({ color: ITEM_DISPLAY_NAME_COLOR,
- font_name: "Sans 14px",
- line_wrap: true,
- text: this._description.text });
- textDetails.append(detailsDescription, Big.BoxPackFlags.NONE);
+ let detailsDescription = new St.Label({ text: this._description.text });
+ textDetails.add(detailsDescription);
this._detailsDescriptions.push(detailsDescription);
@@ -223,7 +194,7 @@ GenericDisplayItem.prototype = {
// Destroys the item.
destroy: function() {
- this.actor.destroy();
+ this.actor.destroy();
},
//// Pure virtual public methods ////
@@ -260,20 +231,15 @@ GenericDisplayItem.prototype = {
}
this._icon = this._createIcon();
- this._iconBox.append(this._icon, Big.BoxPackFlags.NONE);
+ this._iconBin.set_child(this._icon);
- this._name = new Clutter.Text({ color: ITEM_DISPLAY_NAME_COLOR,
- font_name: "Sans 14px",
- ellipsize: Pango.EllipsizeMode.END,
- text: nameText });
- this._infoText.append(this._name, Big.BoxPackFlags.EXPAND);
+ this._name = new St.Label({ style_class: "generic-display-item-name",
+ text: nameText });
+ this._infoText.add(this._name);
- this._description = new Clutter.Text({ color: ITEM_DISPLAY_DESCRIPTION_COLOR,
- font_name: "Sans 12px",
- ellipsize: Pango.EllipsizeMode.END,
- text: descriptionText ? descriptionText : ""
- });
- this._infoText.append(this._description, Big.BoxPackFlags.EXPAND);
+ this._description = new St.Label({ style_class: "generic-display-item-description",
+ text: descriptionText ? descriptionText : "" });
+ this._infoText.add(this._description);
},
// Sets the description text for the item, including the description text
@@ -319,31 +285,36 @@ GenericDisplayItem.prototype = {
Signals.addSignalMethods(GenericDisplayItem.prototype);
+const GenericDisplayFlags = {
+ DISABLE_VSCROLLING: 1 << 0
+}
+
/* This is a virtual class that represents a display containing a collection of items
* that can be filtered with a search string.
*/
-function GenericDisplay() {
- this._init();
+function GenericDisplay(flags) {
+ this._init(flags);
}
GenericDisplay.prototype = {
- _init : function() {
+ _init : function(flags) {
+ let disableVScrolling = (flags & GenericDisplayFlags.DISABLE_VSCROLLING) != 0;
this._search = '';
this._expanded = false;
- this._maxItemsPerPage = null;
- this._list = new Shell.OverflowList({ spacing: 6.0,
- item_height: ITEM_DISPLAY_HEIGHT });
-
- this._list.connect('notify::n-pages', Lang.bind(this, function () {
- this._updateDisplayControl(true);
- }));
- this._list.connect('notify::page', Lang.bind(this, function () {
- this._updateDisplayControl(false);
- }));
+ if (disableVScrolling) {
+ this.actor = this._list = new Shell.OverflowList({ spacing: 6,
+ item_height: 50 });
+ } else {
+ this.actor = new St.ScrollView({ x_fill: true, y_fill: true });
+ this.actor.get_hscroll_bar().hide();
+ this._list = new St.BoxLayout({ style_class: 'generic-display-container',
+ vertical: true });
+ this.actor.add_actor(this._list);
+ }
this._pendingRedisplay = RedisplayFlags.NONE;
- this._list.connect('notify::mapped', Lang.bind(this, this._onMappedNotify));
+ this.actor.connect('notify::mapped', Lang.bind(this, this._onMappedNotify));
// map where Object represents the item info
this._allItems = {};
@@ -355,13 +326,6 @@ GenericDisplay.prototype = {
this._displayedItems = {};
this._openDetailIndex = -1;
this._selectedIndex = -1;
- // These two are public - .actor is the normal "actor subclass" property,
- // but we also expose a .displayControl actor which is separate.
- // See also getNavigationArea.
- this.actor = this._list;
- this.displayControl = new Big.Box({ background_color: ITEM_DISPLAY_BACKGROUND_COLOR,
- spacing: 12,
- orientation: Big.BoxOrientation.HORIZONTAL});
},
//// Public methods ////
@@ -369,16 +333,18 @@ GenericDisplay.prototype = {
// Sets the search string and displays the matching items.
setSearch: function(text) {
let lowertext = text.toLowerCase();
- if (lowertext == this._search)
+ if (lowertext == this._search) {
return;
- let flags = RedisplayFlags.RESET_CONTROLS;
+ }
+ let flags = RedisplayFlags.IMMEDIATE;
if (this._search != '') {
// Because we combine search terms with OR, we have to be sure that no new term
// was introduced before deciding that the new search results will be a subset of
// the existing search results.
if (lowertext.indexOf(this._search) == 0 &&
- lowertext.split(/\s+/).length == this._search.split(/\s+/).length)
+ lowertext.split(/\s+/).length == this._search.split(/\s+/).length) {
flags |= RedisplayFlags.SUBSEARCH;
+ }
}
this._search = lowertext;
this._redisplay(flags);
@@ -398,7 +364,7 @@ GenericDisplay.prototype = {
// to the bottom one. Returns true if the selection actually moved up, false if it wrapped
// around to the bottom.
selectUp: function() {
- let count = this._list.displayedCount;
+ let count = this._getVisibleCount();
let selectedUp = true;
let prev = this._selectedIndex - 1;
if (this._selectedIndex <= 0) {
@@ -413,7 +379,7 @@ GenericDisplay.prototype = {
// to the top one. Returns true if the selection actually moved down, false if it wrapped
// around to the top.
selectDown: function() {
- let count = this._list.displayedCount;
+ let count = this._getVisibleCount();
let selectedDown = true;
let next = this._selectedIndex + 1;
if (this._selectedIndex == count - 1) {
@@ -432,7 +398,7 @@ GenericDisplay.prototype = {
// Selects the last item among the displayed items.
selectLastItem: function() {
- let count = this._list.displayedCount;
+ let count = this._getVisibleCount();
if (this.hasItems())
this._selectIndex(count - 1);
},
@@ -469,6 +435,8 @@ GenericDisplay.prototype = {
resetState: function() {
this._filterReset();
this._openDetailIndex = -1;
+ if (!(this.actor instanceof Shell.OverflowList))
+ this.actor.get_vscroll_bar().get_adjustment().value = 0;
},
// Returns an actor which acts as a sidebar; this is used for
@@ -482,15 +450,6 @@ GenericDisplay.prototype = {
return item.createDetailsActor();
},
- // Displays the page specified by the pageNumber argument.
- displayPage: function(pageNumber) {
- // Cleanup from the previous selection, but don't unset this._selectedIndex
- if (this.hasSelected()) {
- this._findDisplayedByIndex(this._selectedIndex).markSelected(false);
- }
- this._list.page = pageNumber;
- },
-
//// Protected methods ////
_recreateDisplayItems: function() {
@@ -516,14 +475,14 @@ GenericDisplay.prototype = {
Lang.bind(this,
function() {
// update the selection
- this._selectIndex(this._list.get_actor_index(displayItem.actor));
+ this._selectIndex(this._list.get_children().indexOf(displayItem.actor));
this.activateSelected();
}));
displayItem.connect('show-details',
Lang.bind(this,
function() {
- let index = this._list.get_actor_index(displayItem.actor);
+ let index = this._list.get_children().indexOf(displayItem.actor);
/* Close the details pane if already open */
if (index == this._openDetailIndex) {
this._openDetailIndex = -1;
@@ -538,9 +497,10 @@ GenericDisplay.prototype = {
// Removes an item identifed by the itemId from the displayed items.
_removeDisplayItem: function(itemId) {
- let count = this._list.displayedCount;
+ let children = this._list.get_children();
+ let count = children.length;
let displayItem = this._displayedItems[itemId];
- let displayItemIndex = this._list.get_actor_index(displayItem.actor);
+ let displayItemIndex = children.indexOf(displayItem.actor);
if (this.hasSelected() && count == 1) {
this.unsetSelected();
@@ -635,24 +595,22 @@ GenericDisplay.prototype = {
/*
* Updates the displayed items, applying the search string if one exists.
* @flags: Flags controlling redisplay behavior as follows:
- * RESET_CONTROLS - indicates if the page selection should be reset when displaying the matching results.
- * We reset the page selection when the change in results was initiated by the user by
- * entering a different search criteria or by viewing the results list in a different
- * size mode, but we keep the page selection the same if the results got updated on
- * their own while the user was browsing through the result pages.
* SUBSEARCH - Indicates that the current _search is a superstring of the previous
* one, which implies we only need to re-search through previous results.
- * FULL - Indicates that we need recreate all displayed items; implies RESET_CONTROLS as well
+ * FULL - Indicates that we need recreate all displayed items.
+ * IMMEDIATE - Do the full redisplay even if we're not mapped. This is useful
+ * if you want to get the number of matched items and show/hide a section based on
+ * that number.
*/
_redisplay: function(flags) {
- if (!this._list.mapped) {
+ let immediate = (flags & RedisplayFlags.IMMEDIATE) != 0;
+ if (!immediate && !this.actor.mapped) {
this._pendingRedisplay |= flags;
return;
}
- let isSubSearch = (flags & RedisplayFlags.SUBSEARCH) > 0;
- let fullReload = (flags & RedisplayFlags.FULL) > 0;
- let resetPage = (flags & RedisplayFlags.RESET_CONTROLS) > 0 || fullReload;
+ let isSubSearch = (flags & RedisplayFlags.SUBSEARCH) != 0;
+ let fullReload = (flags & RedisplayFlags.FULL) != 0;
let hadSelected = this.hasSelected();
this.unsetSelected();
@@ -674,9 +632,6 @@ GenericDisplay.prototype = {
this._redisplayReordering();
}
- if (resetPage)
- this._list.page = 0;
-
if (hadSelected) {
this._selectedIndex = -1;
this.selectFirstItem();
@@ -776,59 +731,14 @@ GenericDisplay.prototype = {
return matchScores;
},
- /*
- * Updates the display control to reflect the matched items set and the page selected.
- *
- * resetDisplayControl - indicates if the display control should be re-created because
- * the results or the space allocated for them changed. If it's false,
- * the existing display control is used and only the page links are
- * updated to reflect the current page selection.
- */
- _updateDisplayControl: function(resetDisplayControl) {
- if (resetDisplayControl) {
- this.displayControl.remove_all();
- let nPages = this._list.n_pages;
- // Don't show the page indicator if there is only one page.
- if (nPages == 1)
- return;
- let pageNumber = this._list.page;
- for (let i = 0; i < nPages; i++) {
- let pageControl = new Link.Link({ color: (i == pageNumber) ? DISPLAY_CONTROL_SELECTED_COLOR : ITEM_DISPLAY_DESCRIPTION_COLOR,
- font_name: "Sans Bold 16px",
- text: (i+1) + "",
- reactive: (i == pageNumber) ? false : true});
- this.displayControl.append(pageControl.actor, Big.BoxPackFlags.NONE);
-
- // we use pageNumberLocalScope to get the page number right in the callback function
- let pageNumberLocalScope = i;
- pageControl.connect('clicked',
- Lang.bind(this,
- function(o, event) {
- this.displayPage(pageNumberLocalScope);
- }));
- }
- } else {
- let pageControlActors = this.displayControl.get_children();
- for (let i = 0; i < pageControlActors.length; i++) {
- let pageControlActor = pageControlActors[i];
- if (i == this._list.page) {
- pageControlActor.color = DISPLAY_CONTROL_SELECTED_COLOR;
- pageControlActor.reactive = false;
- } else {
- pageControlActor.color = ITEM_DISPLAY_DESCRIPTION_COLOR;
- pageControlActor.reactive = true;
- }
- }
- }
- if (this.hasSelected()) {
- this.selectFirstItem();
- }
- },
-
// Returns a display item based on its index in the ordering of the
// display children.
_findDisplayedByIndex: function(index) {
- let actor = this._list.get_displayed_actor(index);
+ let actor;
+ if (this.actor instanceof Shell.OverflowList)
+ actor = this.actor.get_displayed_actor(index);
+ else
+ actor = this._list.get_children()[index];
return this._findDisplayedByActor(actor);
},
@@ -862,8 +772,14 @@ GenericDisplay.prototype = {
this.emit('selected');
},
+ _getVisibleCount: function() {
+ if (this.actor instanceof Shell.OverflowList)
+ return this._list.displayed_count;
+ return this._list.get_n_children();
+ },
+
_onMappedNotify: function () {
- let mapped = this._list.mapped;
+ let mapped = this.actor.mapped;
if (mapped && this._pendingRedisplay > RedisplayFlags.NONE)
this._redisplay(this._pendingRedisplay);
diff --git a/js/ui/lookingGlass.js b/js/ui/lookingGlass.js
index 35431f0ad..afe99b864 100644
--- a/js/ui/lookingGlass.js
+++ b/js/ui/lookingGlass.js
@@ -320,6 +320,10 @@ LookingGlass.prototype = {
this._savedText = null;
this._historyNavIndex = -1;
this._history = [];
+ this._borderPaintTarget = null;
+ this._borderPaintId = 0;
+ this._borderDestroyId = 0;
+
this._readHistory();
this._open = false;
@@ -487,6 +491,18 @@ LookingGlass.prototype = {
this._results.push(result);
this._resultsArea.append(result.actor, Big.BoxPackFlags.NONE);
this._propInspector.setTarget(obj);
+ if (this._borderPaintTarget != null) {
+ this._borderPaintTarget.disconnect(this._borderPaintId);
+ this._borderPaintTarget = null;
+ }
+ if (obj instanceof Clutter.Actor) {
+ this._borderPaintTarget = obj;
+ this._borderPaintId = Shell.add_hook_paint_red_border(obj);
+ this._borderDestroyId = obj.connect('destroy', Lang.bind(this, function () {
+ this._borderDestroyId = 0;
+ this._borderPaintTarget = null;
+ }));
+ }
let children = this._resultsArea.get_children();
if (children.length > this._maxItems) {
this._results.shift();
@@ -582,6 +598,12 @@ LookingGlass.prototype = {
this._open = false;
Tweener.removeTweens(this.actor);
+ if (this._borderPaintTarget != null) {
+ this._borderPaintTarget.disconnect(this._borderPaintId);
+ this._borderPaintTarget.disconnect(this._borderDestroyId);
+ this._borderPaintTarget = null;
+ }
+
Main.popModal(this.actor);
Tweener.addTween(this.actor, { time: 0.5,
diff --git a/js/ui/main.js b/js/ui/main.js
index f0dae6815..0bea5d59e 100644
--- a/js/ui/main.js
+++ b/js/ui/main.js
@@ -18,6 +18,7 @@ const MessageTray = imports.ui.messageTray;
const Messaging = imports.ui.messaging;
const Overview = imports.ui.overview;
const Panel = imports.ui.panel;
+const PlaceDisplay = imports.ui.placeDisplay;
const RunDialog = imports.ui.runDialog;
const LookingGlass = imports.ui.lookingGlass;
const NotificationDaemon = imports.ui.notificationDaemon;
@@ -31,6 +32,7 @@ DEFAULT_BACKGROUND_COLOR.from_pixel(0x2266bbff);
let chrome = null;
let panel = null;
let sidebar = null;
+let placesManager = null;
let overview = null;
let runDialog = null;
let lookingGlass = null;
@@ -102,6 +104,7 @@ function start() {
getRunDialog().open();
});
+ placesManager = new PlaceDisplay.PlacesManager();
overview = new Overview.Overview();
chrome = new Chrome.Chrome();
panel = new Panel.Panel();
diff --git a/js/ui/overview.js b/js/ui/overview.js
index dad7822fa..e217bfe1a 100644
--- a/js/ui/overview.js
+++ b/js/ui/overview.js
@@ -123,8 +123,7 @@ Overview.prototype = {
// Container to hold popup pane chrome.
this._paneContainer = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
- spacing: 6
- });
+ spacing: 6 });
// Note here we explicitly don't set the paneContainer to be reactive yet; that's done
// inside the notify::visible handler on panes.
this._paneContainer.connect('button-release-event', Lang.bind(this, function(background) {
@@ -149,11 +148,11 @@ Overview.prototype = {
// We divide the screen into an imaginary grid which helps us determine the layout of
// different visual components.
if (wideScreen) {
- displayGridColumnWidth = primary.width / COLUMNS_WIDE_SCREEN;
- displayGridRowHeight = primary.height / ROWS_WIDE_SCREEN;
+ displayGridColumnWidth = Math.floor(primary.width / COLUMNS_WIDE_SCREEN);
+ displayGridRowHeight = Math.floor(primary.height / ROWS_WIDE_SCREEN);
} else {
- displayGridColumnWidth = primary.width / COLUMNS_REGULAR_SCREEN;
- displayGridRowHeight = primary.height / ROWS_REGULAR_SCREEN;
+ displayGridColumnWidth = Math.floor(primary.width / COLUMNS_REGULAR_SCREEN);
+ displayGridRowHeight = Math.floor(primary.height / ROWS_REGULAR_SCREEN);
}
},
@@ -175,11 +174,11 @@ Overview.prototype = {
- WORKSPACE_GRID_PADDING * 2;
// We scale the vertical padding by (primary.height / primary.width)
// so that the workspace preserves its aspect ratio.
- this._workspacesHeight = displayGridRowHeight * workspaceRowsUsed
- - WORKSPACE_GRID_PADDING * (primary.height / primary.width) * 2;
+ this._workspacesHeight = Math.floor(displayGridRowHeight * workspaceRowsUsed
+ - WORKSPACE_GRID_PADDING * (primary.height / primary.width) * 2);
this._workspacesX = displayGridColumnWidth + WORKSPACE_GRID_PADDING;
- this._workspacesY = displayGridRowHeight + WORKSPACE_GRID_PADDING * (primary.height / primary.width);
+ this._workspacesY = Math.floor(displayGridRowHeight + WORKSPACE_GRID_PADDING * (primary.height / primary.width));
this._dash.actor.set_position(0, contentY);
this._dash.actor.set_size(displayGridColumnWidth, contentHeight);
@@ -197,9 +196,9 @@ Overview.prototype = {
this._backOver.set_size(global.screen_width, global.screen_height);
this._paneContainer.set_position(this._dash.actor.x + this._dash.actor.width + DEFAULT_PADDING,
- contentY);
+ this._workspacesY);
// Dynamic width
- this._paneContainer.height = contentHeight;
+ this._paneContainer.height = this._workspacesHeight;
this._transparentBackground.set_position(this._paneContainer.x, this._paneContainer.y);
this._transparentBackground.set_size(primary.width - this._paneContainer.x,
@@ -228,6 +227,7 @@ Overview.prototype = {
this._activeDisplayPane.close();
return true;
}));
+ this._workspaces.actor.opacity = 64;
} else if (pane == this._activeDisplayPane) {
this._activeDisplayPane = null;
if (backgroundEventId != null) {
@@ -236,6 +236,7 @@ Overview.prototype = {
}
this._transparentBackground.lower_bottom();
this._paneContainer.lower_bottom();
+ this._workspaces.actor.opacity = 255;
}
}));
},
diff --git a/js/ui/panel.js b/js/ui/panel.js
index 447bb854e..9e2fdb431 100644
--- a/js/ui/panel.js
+++ b/js/ui/panel.js
@@ -16,6 +16,7 @@ const _ = Gettext.gettext;
const Button = imports.ui.button;
const Calendar = imports.ui.calendar;
const Main = imports.ui.main;
+const StatusMenu = imports.ui.statusMenu;
const PANEL_HEIGHT = 26;
const TRAY_HEIGHT = PANEL_HEIGHT - 1;
@@ -176,6 +177,8 @@ Panel.prototype = {
this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL
});
+ this.actor._delegate = this;
+
let backgroundGradient = Shell.create_vertical_gradient(BACKGROUND_TOP,
BACKGROUND_BOTTOM);
this.actor.connect('notify::allocation', Lang.bind(this, function () {
@@ -371,11 +374,8 @@ Panel.prototype = {
this._traymanager.manage_stage(global.stage);
let statusbox = new Big.Box();
- let statusmenu = this._statusmenu = new Shell.StatusMenu();
- statusmenu.get_icon().hide();
- statusmenu.get_name().fontName = DEFAULT_FONT;
- statusmenu.get_name().color = PANEL_FOREGROUND_COLOR;
- statusbox.append(this._statusmenu, Big.BoxPackFlags.NONE);
+ let statusmenu = this._statusmenu = new StatusMenu.StatusMenu();
+ statusbox.append(this._statusmenu.actor, Big.BoxPackFlags.NONE);
let statusbutton = new Button.Button(statusbox,
PANEL_BUTTON_COLOR,
PRESSED_BUTTON_BACKGROUND_COLOR,
@@ -385,7 +385,7 @@ Panel.prototype = {
if (e.get_button() == 1 && e.get_click_count() == 1) {
statusmenu.toggle(e);
// The statusmenu might not pop up if it couldn't get a pointer grab
- if (statusmenu.is_active())
+ if (statusmenu.isActive())
statusbutton.actor.active = true;
return true;
} else {
diff --git a/js/ui/placeDisplay.js b/js/ui/placeDisplay.js
new file mode 100644
index 000000000..f408fc978
--- /dev/null
+++ b/js/ui/placeDisplay.js
@@ -0,0 +1,540 @@
+/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
+
+const Big = imports.gi.Big;
+const Clutter = imports.gi.Clutter;
+const Pango = imports.gi.Pango;
+const GLib = imports.gi.GLib;
+const Gio = imports.gi.Gio;
+const Shell = imports.gi.Shell;
+const Lang = imports.lang;
+const Mainloop = imports.mainloop;
+const Signals = imports.signals;
+const St = imports.gi.St;
+const Gettext = imports.gettext.domain('gnome-shell');
+const _ = Gettext.gettext;
+
+const DND = imports.ui.dnd;
+const Main = imports.ui.main;
+const GenericDisplay = imports.ui.genericDisplay;
+
+const NAUTILUS_PREFS_DIR = '/apps/nautilus/preferences';
+const DESKTOP_IS_HOME_KEY = NAUTILUS_PREFS_DIR + '/desktop_is_home_dir';
+
+const PLACES_ICON_SIZE = 16;
+
+/**
+ * Represents a place object, which is most normally a bookmark entry,
+ * a mount/volume, or a special place like the Home Folder, Computer, and Network.
+ *
+ * @name: String title
+ * @iconFactory: A JavaScript callback which will create an icon texture given a size parameter
+ * @launch: A JavaScript callback to launch the entry
+ */
+function PlaceInfo(name, iconFactory, launch) {
+ this._init(name, iconFactory, launch);
+}
+
+PlaceInfo.prototype = {
+ _init: function(name, iconFactory, launch) {
+ this.name = name;
+ this.iconFactory = iconFactory;
+ this.launch = launch;
+ this.id = null;
+ }
+}
+
+function PlacesManager() {
+ this._init();
+}
+
+PlacesManager.prototype = {
+ _init: function() {
+ let gconf = Shell.GConf.get_default();
+ gconf.watch_directory(NAUTILUS_PREFS_DIR);
+
+ this._mounts = [];
+ this._bookmarks = [];
+ this._isDesktopHome = false;
+
+ let homeFile = Gio.file_new_for_path (GLib.get_home_dir());
+ let homeUri = homeFile.get_uri();
+ let homeLabel = Shell.util_get_label_for_uri (homeUri);
+ let homeIcon = Shell.util_get_icon_for_uri (homeUri);
+ this._home = new PlaceInfo(homeLabel,
+ function(size) {
+ return Shell.TextureCache.get_default().load_gicon(homeIcon, size);
+ },
+ function() {
+ Gio.app_info_launch_default_for_uri(homeUri, Main.createAppLaunchContext());
+ });
+
+ let desktopPath = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DESKTOP);
+ let desktopFile = Gio.file_new_for_path (desktopPath);
+ let desktopUri = desktopFile.get_uri();
+ let desktopLabel = Shell.util_get_label_for_uri (desktopUri);
+ let desktopIcon = Shell.util_get_icon_for_uri (desktopUri);
+ this._desktopMenu = new PlaceInfo(desktopLabel,
+ function(size) {
+ return Shell.TextureCache.get_default().load_gicon(desktopIcon, size);
+ },
+ function() {
+ Gio.app_info_launch_default_for_uri(desktopUri, Main.createAppLaunchContext());
+ });
+
+ this._connect = new PlaceInfo(_("Connect to..."),
+ function (size) {
+ return Shell.TextureCache.get_default().load_icon_name("applications-internet", size);
+ },
+ function () {
+ new Shell.Process({ args: ['nautilus-connect-server'] }).run();
+ });
+
+ let networkApp = null;
+ try {
+ networkApp = Shell.AppSystem.get_default().load_from_desktop_file('gnome-network-scheme.desktop');
+ } catch(e) {
+ try {
+ networkApp = Shell.AppSystem.get_default().load_from_desktop_file('network-scheme.desktop');
+ } catch(e) {
+ log("Cannot create \"Network\" item, .desktop file not found or corrupt.");
+ }
+ }
+
+ if (networkApp != null) {
+ this._network = new PlaceInfo(networkApp.get_name(),
+ function(size) {
+ return networkApp.create_icon_texture(size);
+ },
+ function () {
+ networkApp.launch();
+ });
+ }
+
+ /*
+ * Show devices, code more or less ported from nautilus-places-sidebar.c
+ */
+ this._volumeMonitor = Gio.VolumeMonitor.get();
+ this._volumeMonitor.connect('volume-added', Lang.bind(this, this._updateDevices));
+ this._volumeMonitor.connect('volume-removed',Lang.bind(this, this._updateDevices));
+ this._volumeMonitor.connect('volume-changed', Lang.bind(this, this._updateDevices));
+ this._volumeMonitor.connect('mount-added', Lang.bind(this, this._updateDevices));
+ this._volumeMonitor.connect('mount-removed', Lang.bind(this, this._updateDevices));
+ this._volumeMonitor.connect('mount-changed', Lang.bind(this, this._updateDevices));
+ this._volumeMonitor.connect('drive-connected', Lang.bind(this, this._updateDevices));
+ this._volumeMonitor.connect('drive-disconnected', Lang.bind(this, this._updateDevices));
+ this._volumeMonitor.connect('drive-changed', Lang.bind(this, this._updateDevices));
+ this._updateDevices();
+
+ this._bookmarksPath = GLib.build_filenamev([GLib.get_home_dir(), ".gtk-bookmarks"]);
+ this._bookmarksFile = Gio.file_new_for_path(this._bookmarksPath);
+ let monitor = this._bookmarksFile.monitor_file(Gio.FileMonitorFlags.NONE, null);
+ this._bookmarkTimeoutId = 0;
+ monitor.connect('changed', Lang.bind(this, function () {
+ if (this._bookmarkTimeoutId > 0)
+ return;
+ /* Defensive event compression */
+ this._bookmarkTimeoutId = Mainloop.timeout_add(100, Lang.bind(this, function () {
+ this._bookmarkTimeoutId = 0;
+ this._reloadBookmarks();
+ return false;
+ }));
+ }));
+
+ this._reloadBookmarks();
+ this._updateDesktopMenuVisibility();
+
+ gconf.connect('changed::' + DESKTOP_IS_HOME_KEY, Lang.bind(this, this._updateDesktopMenuVisibility));
+
+ },
+
+ _updateDevices: function() {
+ this._mounts = [];
+
+ /* first go through all connected drives */
+ let drives = this._volumeMonitor.get_connected_drives();
+ for (let i = 0; i < drives.length; i++) {
+ let volumes = drives[i].get_volumes();
+ for(let j = 0; j < volumes.length; j++) {
+ let mount = volumes[j].get_mount();
+ if(mount != null) {
+ this._addMount(mount);
+ }
+ }
+ }
+
+ /* add all volumes that is not associated with a drive */
+ let volumes = this._volumeMonitor.get_volumes();
+ for(let i = 0; i < volumes.length; i++) {
+ if(volumes[i].get_drive() != null)
+ continue;
+
+ let mount = volumes[i].get_mount();
+ if(mount != null) {
+ this._addMount(mount);
+ }
+ }
+
+ /* add mounts that have no volume (/etc/mtab mounts, ftp, sftp,...) */
+ let mounts = this._volumeMonitor.get_mounts();
+ for(let i = 0; i < mounts.length; i++) {
+ if(mounts[i].is_shadowed())
+ continue;
+
+ if(mounts[i].get_volume())
+ continue;
+
+ this._addMount(mounts[i]);
+ }
+
+ /* We emit two signals, one for a generic 'all places' update
+ * and the other for one specific to mounts. We do this because
+ * clients like PlaceDisplay may only care about places in general
+ * being updated while clients like DashPlaceDisplay care which
+ * specific type of place got updated.
+ */
+ this.emit('mounts-updated');
+ this.emit('places-updated');
+
+ },
+
+ _reloadBookmarks: function() {
+
+ this._bookmarks = [];
+
+ if (!GLib.file_test(this._bookmarksPath, GLib.FileTest.EXISTS))
+ return;
+
+ let [success, bookmarksContent, len] = GLib.file_get_contents(this._bookmarksPath);
+
+ if (!success)
+ return;
+
+ let bookmarks = bookmarksContent.split('\n');
+
+ let bookmarksToLabel = {};
+ let bookmarksOrder = [];
+ for (let i = 0; i < bookmarks.length; i++) {
+ let bookmarkLine = bookmarks[i];
+ let components = bookmarkLine.split(' ');
+ let bookmark = components[0];
+ if (bookmark in bookmarksToLabel)
+ continue;
+ let label = null;
+ if (components.length > 1)
+ label = components.slice(1).join(' ');
+ bookmarksToLabel[bookmark] = label;
+ bookmarksOrder.push(bookmark);
+ }
+
+ for (let i = 0; i < bookmarksOrder.length; i++) {
+ let bookmark = bookmarksOrder[i];
+ let label = bookmarksToLabel[bookmark];
+ let file = Gio.file_new_for_uri(bookmark);
+ if (!file.query_exists(null))
+ continue;
+ if (label == null)
+ label = Shell.util_get_label_for_uri(bookmark);
+ if (label == null)
+ continue;
+ let icon = Shell.util_get_icon_for_uri(bookmark);
+
+ let item = new PlaceInfo(label,
+ function(size) {
+ return Shell.TextureCache.get_default().load_gicon(icon, size);
+ },
+ function() {
+ Gio.app_info_launch_default_for_uri(bookmark, Main.createAppLaunchContext());
+ });
+ this._bookmarks.push(item);
+ }
+
+ /* See comment in _updateDevices for explanation why there are two signals. */
+ this.emit('bookmarks-updated');
+ this.emit('places-updated');
+ },
+
+ _updateDesktopMenuVisibility: function() {
+ let gconf = Shell.GConf.get_default();
+ this._isDesktopHome = gconf.get_boolean(DESKTOP_IS_HOME_KEY);
+
+ /* See comment in _updateDevices for explanation why there are two signals. */
+ this.emit('defaults-updated');
+ this.emit('places-updated');
+ },
+
+ _addMount: function(mount) {
+ let mountLabel = mount.get_name();
+ let mountIcon = mount.get_icon();
+ let root = mount.get_root();
+ let mountUri = root.get_uri();
+ let devItem = new PlaceInfo(mountLabel,
+ function(size) {
+ return Shell.TextureCache.get_default().load_gicon(mountIcon, size);
+ },
+ function() {
+ Gio.app_info_launch_default_for_uri(mountUri, Main.createAppLaunchContext());
+ });
+ this._mounts.push(devItem);
+ },
+
+ getAllPlaces: function () {
+ return this.getDefaultPlaces().concat(this.getBookmarks(), this.getMounts());
+ },
+
+ getDefaultPlaces: function () {
+ let places = [this._home];
+
+ if (!this._isDesktopHome)
+ places.push(this._desktopMenu);
+
+ if (this._network)
+ places.push(this._network);
+
+ places.push(this._connect);
+ return places;
+ },
+
+ getBookmarks: function () {
+ return this._bookmarks;
+ },
+
+ getMounts: function () {
+ return this._mounts;
+ }
+};
+
+Signals.addSignalMethods(PlacesManager.prototype);
+
+/**
+ * An entry in the places menu.
+ * @info The corresponding PlaceInfo to populate this entry.
+ */
+function DashPlaceDisplayItem(info) {
+ this._init(info);
+}
+
+DashPlaceDisplayItem.prototype = {
+ _init: function(info) {
+ this.name = info.name;
+ this._info = info;
+ this._icon = info.iconFactory(PLACES_ICON_SIZE);
+ this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
+ reactive: true,
+ spacing: 4 });
+ this.actor.connect('button-release-event', Lang.bind(this, function (b, e) {
+ this._info.launch();
+ Main.overview.hide();
+ }));
+ let text = new St.Label({ style_class: 'places-item',
+ text: info.name });
+ let iconBox = new Big.Box({ y_align: Big.BoxAlignment.CENTER });
+ iconBox.append(this._icon, Big.BoxPackFlags.NONE);
+ this.actor.append(iconBox, Big.BoxPackFlags.NONE);
+ this.actor.append(text, Big.BoxPackFlags.EXPAND);
+
+ this.actor._delegate = this;
+ let draggable = DND.makeDraggable(this.actor);
+ },
+
+ getDragActorSource: function() {
+ return this._icon;
+ },
+
+ getDragActor: function(stageX, stageY) {
+ return this._info.iconFactory(PLACES_ICON_SIZE);
+ },
+
+ //// Drag and drop methods ////
+
+ shellWorkspaceLaunch: function() {
+ this._info.launch();
+ }
+};
+
+function DashPlaceDisplay() {
+ this._init();
+}
+
+DashPlaceDisplay.prototype = {
+ _init: function() {
+
+ // Places is divided semi-arbitrarily into left and right; a grid would
+ // look better in that there would be an even number of items left+right,
+ // but it seems like we want some sort of differentiation between actions
+ // like "Connect to server..." and regular folders
+ this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
+ spacing: 4 });
+ this._leftBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL });
+ this.actor.append(this._leftBox, Big.BoxPackFlags.EXPAND);
+ this._rightBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL });
+ this.actor.append(this._rightBox, Big.BoxPackFlags.EXPAND);
+
+ // Subdivide left into actions and devices
+ this._actionsBox = new St.BoxLayout({ style_class: 'places-actions',
+ vertical: true });
+
+ this._devBox = new St.BoxLayout({ style_class: 'places-actions',
+ name: 'placesDevices',
+ vertical: true });
+
+ this._dirsBox = new St.BoxLayout({ style_class: 'places-actions',
+ vertical: true });
+
+ this._leftBox.append(this._actionsBox, Big.BoxPackFlags.NONE);
+ this._leftBox.append(this._devBox, Big.BoxPackFlags.NONE);
+
+ this._rightBox.append(this._dirsBox, Big.BoxPackFlags.NONE);
+
+ Main.placesManager.connect('defaults-updated', Lang.bind(this, this._updateDefaults));
+ Main.placesManager.connect('bookmarks-updated', Lang.bind(this, this._updateBookmarks));
+ Main.placesManager.connect('mounts-updated', Lang.bind(this, this._updateMounts));
+
+ this._updateDefaults();
+ this._updateMounts();
+ this._updateBookmarks();
+ },
+
+ _updateDefaults: function() {
+ this._actionsBox.destroy_children();
+
+ let places = Main.placesManager.getDefaultPlaces();
+ for (let i = 0; i < places.length; i++)
+ this._actionsBox.add(new DashPlaceDisplayItem(places[i]).actor);
+ },
+
+ _updateMounts: function() {
+ this._devBox.destroy_children();
+
+ let places = Main.placesManager.getMounts();
+ for (let i = 0; i < places.length; i++)
+ this._devBox.add(new DashPlaceDisplayItem(places[i]).actor);
+ },
+
+ _updateBookmarks: function() {
+ this._dirsBox.destroy_children();
+
+ let places = Main.placesManager.getBookmarks();
+ for (let i = 0; i < places.length; i ++)
+ this._dirsBox.add(new DashPlaceDisplayItem(places[i]).actor);
+ }
+};
+
+Signals.addSignalMethods(DashPlaceDisplay.prototype);
+
+
+function PlaceDisplayItem(placeInfo) {
+ this._init(placeInfo);
+}
+
+PlaceDisplayItem.prototype = {
+ __proto__: GenericDisplay.GenericDisplayItem.prototype,
+
+ _init : function(placeInfo) {
+ GenericDisplay.GenericDisplayItem.prototype._init.call(this);
+ this._info = placeInfo;
+
+ this._setItemInfo(placeInfo.name, '');
+ },
+
+ //// Public method overrides ////
+
+ // Opens an application represented by this display item.
+ launch : function() {
+ this._info.launch();
+ },
+
+ shellWorkspaceLaunch: function() {
+ this._info.launch();
+ },
+
+ //// Protected method overrides ////
+
+ // Returns an icon for the item.
+ _createIcon: function() {
+ return this._info.iconFactory(GenericDisplay.ITEM_DISPLAY_ICON_SIZE);
+ },
+
+ // Returns a preview icon for the item.
+ _createPreviewIcon: function() {
+ return this._info.iconFactory(GenericDisplay.PREVIEW_ICON_SIZE);
+ }
+
+};
+
+function PlaceDisplay(flags) {
+ this._init(flags);
+}
+
+PlaceDisplay.prototype = {
+ __proto__: GenericDisplay.GenericDisplay.prototype,
+
+ _init: function(flags) {
+ GenericDisplay.GenericDisplay.prototype._init.call(this, flags);
+ this._stale = true;
+ Main.placesManager.connect('places-updated', Lang.bind(this, function (e) {
+ this._stale = true;
+ }));
+ },
+
+ //// Protected method overrides ////
+ _refreshCache: function () {
+ if (!this._stale)
+ return true;
+ this._allItems = {};
+ let array = Main.placesManager.getAllPlaces();
+ for (let i = 0; i < array.length; i ++) {
+ // We are using an array id as placeInfo id because placeInfo doesn't have any
+ // other information piece that can be used as a unique id. There are different
+ // types of placeInfo, such as devices and directories that would result in differently
+ // structured ids. Also the home directory can show up in both the default places and in
+ // bookmarks which means its URI can't be used as a unique id. (This does mean it can
+ // appear twice in search results, though that doesn't happen at the moment because we
+ // name it "Home Folder" in default places and it's named with the user's system name
+ // if it appears as a bookmark.)
+ let placeInfo = array[i];
+ placeInfo.id = i;
+ this._allItems[i] = placeInfo;
+ }
+ this._stale = false;
+ return false;
+ },
+
+ // Sets the list of the displayed items.
+ _setDefaultList: function() {
+ this._matchedItems = {};
+ this._matchedItemKeys = [];
+ for (id in this._allItems) {
+ this._matchedItems[id] = 1;
+ this._matchedItemKeys.push(id);
+ }
+ this._matchedItemKeys.sort(Lang.bind(this, this._compareItems));
+ },
+
+ // Checks if the item info can be a match for the search string by checking
+ // the name of the place. Item info is expected to be PlaceInfo.
+ // Returns a boolean flag indicating if itemInfo is a match.
+ _isInfoMatching: function(itemInfo, search) {
+ if (search == null || search == '')
+ return true;
+
+ let name = itemInfo.name.toLowerCase();
+ if (name.indexOf(search) >= 0)
+ return true;
+
+ return false;
+ },
+
+ // Compares items associated with the item ids based on the alphabetical order
+ // of the item names.
+ // Returns an integer value indicating the result of the comparison.
+ _compareItems: function(itemIdA, itemIdB) {
+ let placeA = this._allItems[itemIdA];
+ let placeB = this._allItems[itemIdB];
+ return placeA.name.localeCompare(placeB.name);
+ },
+
+ // Creates a PlaceDisplayItem based on itemInfo, which is expected to be a PlaceInfo object.
+ _createDisplayItem: function(itemInfo) {
+ return new PlaceDisplayItem(itemInfo);
+ }
+};
diff --git a/js/ui/places.js b/js/ui/places.js
deleted file mode 100644
index 9aa604de5..000000000
--- a/js/ui/places.js
+++ /dev/null
@@ -1,321 +0,0 @@
-/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
-
-const Big = imports.gi.Big;
-const Clutter = imports.gi.Clutter;
-const Pango = imports.gi.Pango;
-const GLib = imports.gi.GLib;
-const Gio = imports.gi.Gio;
-const Shell = imports.gi.Shell;
-const Lang = imports.lang;
-const Mainloop = imports.mainloop;
-const Signals = imports.signals;
-const Gettext = imports.gettext.domain('gnome-shell');
-const _ = Gettext.gettext;
-
-const DND = imports.ui.dnd;
-const Main = imports.ui.main;
-const GenericDisplay = imports.ui.genericDisplay;
-
-const NAUTILUS_PREFS_DIR = '/apps/nautilus/preferences';
-const DESKTOP_IS_HOME_KEY = NAUTILUS_PREFS_DIR + '/desktop_is_home_dir';
-
-const PLACES_VSPACING = 8;
-const PLACES_ICON_SIZE = 16;
-
-/**
- * An entry in the places menu.
- * @name: String title
- * @iconFactory: A JavaScript callback which will create an icon texture
- * @onActivate: A JavaScript callback to launch the entry
- */
-function PlaceDisplay(name, iconFactory, onActivate) {
- this._init(name, iconFactory, onActivate);
-}
-
-PlaceDisplay.prototype = {
- _init : function(name, iconFactory, onActivate) {
- this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
- reactive: true,
- spacing: 4 });
- this.actor.connect('button-release-event', Lang.bind(this, function (b, e) {
- onActivate(this);
- Main.overview.hide();
- }));
- let text = new Clutter.Text({ font_name: "Sans 14px",
- ellipsize: Pango.EllipsizeMode.END,
- color: GenericDisplay.ITEM_DISPLAY_NAME_COLOR,
- text: name });
- let iconBox = new Big.Box({ y_align: Big.BoxAlignment.CENTER });
- this._icon = iconFactory();
- iconBox.append(this._icon, Big.BoxPackFlags.NONE);
- this.actor.append(iconBox, Big.BoxPackFlags.NONE);
- this.actor.append(text, Big.BoxPackFlags.EXPAND);
-
- this._iconFactory = iconFactory;
- this._onActivate = onActivate;
-
- this.actor._delegate = this;
- let draggable = DND.makeDraggable(this.actor);
- },
-
- getDragActorSource: function() {
- return this._icon;
- },
-
- getDragActor: function(stageX, stageY) {
- return this._iconFactory();
- },
-
- //// Drag and drop methods ////
-
- shellWorkspaceLaunch : function() {
- this._onActivate();
- }
-};
-Signals.addSignalMethods(PlaceDisplay.prototype);
-
-function Places() {
- this._init();
-}
-
-Places.prototype = {
- _init : function() {
- // Places is divided semi-arbitrarily into left and right; a grid would
- // look better in that there would be an even number of items left+right,
- // but it seems like we want some sort of differentiation between actions
- // like "Connect to server..." and regular folders
- this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
- spacing: 4 });
- this._leftBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL });
- this.actor.append(this._leftBox, Big.BoxPackFlags.EXPAND);
- this._rightBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL });
- this.actor.append(this._rightBox, Big.BoxPackFlags.EXPAND);
-
- // Subdivide left into actions and devices
- this._actionsBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
- spacing: PLACES_VSPACING });
- this._leftBox.append(this._actionsBox, Big.BoxPackFlags.NONE);
- this._devBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
- spacing: PLACES_VSPACING,
- padding_top: 6 });
- this._leftBox.append(this._devBox, Big.BoxPackFlags.NONE);
-
- // Right is bookmarks
- this._dirsBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
- spacing: PLACES_VSPACING });
- this._rightBox.append(this._dirsBox, Big.BoxPackFlags.NONE);
-
- let gconf = Shell.GConf.get_default();
- gconf.watch_directory(NAUTILUS_PREFS_DIR);
-
- let homeFile = Gio.file_new_for_path (GLib.get_home_dir());
- let homeUri = homeFile.get_uri();
- let homeLabel = Shell.util_get_label_for_uri (homeUri);
- let homeIcon = Shell.util_get_icon_for_uri (homeUri);
- let home = new PlaceDisplay(homeLabel,
- function() {
- return Shell.TextureCache.get_default().load_gicon(homeIcon, PLACES_ICON_SIZE);
- },
- function() {
- Gio.app_info_launch_default_for_uri(homeUri, Main.createAppLaunchContext());
- });
-
- this._actionsBox.append(home.actor, Big.BoxPackFlags.NONE);
-
- let desktopPath = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DESKTOP);
- let desktopFile = Gio.file_new_for_path (desktopPath);
- let desktopUri = desktopFile.get_uri();
- let desktopLabel = Shell.util_get_label_for_uri (desktopUri);
- let desktopIcon = Shell.util_get_icon_for_uri (desktopUri);
- this._desktopMenu = new PlaceDisplay(desktopLabel,
- function() {
- return Shell.TextureCache.get_default().load_gicon(desktopIcon, PLACES_ICON_SIZE);
- },
- function() {
- Gio.app_info_launch_default_for_uri(desktopUri, Main.createAppLaunchContext());
- });
- this._actionsBox.append(this._desktopMenu.actor, Big.BoxPackFlags.NONE);
- this._updateDesktopMenuVisibility();
- gconf.connect('changed::' + DESKTOP_IS_HOME_KEY, Lang.bind(this, this._updateDesktopMenuVisibility));
-
- /*
- * Show devices, code more or less ported from nautilus-places-sidebar.c
- */
- this._volumeMonitor = Gio.VolumeMonitor.get();
- this._volumeMonitor.connect('volume-added', Lang.bind(this, this._updateDevices));
- this._volumeMonitor.connect('volume-removed',Lang.bind(this, this._updateDevices));
- this._volumeMonitor.connect('volume-changed', Lang.bind(this, this._updateDevices));
- this._volumeMonitor.connect('mount-added', Lang.bind(this, this._updateDevices));
- this._volumeMonitor.connect('mount-removed', Lang.bind(this, this._updateDevices));
- this._volumeMonitor.connect('mount-changed', Lang.bind(this, this._updateDevices));
- this._volumeMonitor.connect('drive-connected', Lang.bind(this, this._updateDevices));
- this._volumeMonitor.connect('drive-disconnected', Lang.bind(this, this._updateDevices));
- this._volumeMonitor.connect('drive-changed', Lang.bind(this, this._updateDevices));
- this._updateDevices();
-
- let networkApp = null;
- try {
- networkApp = Shell.AppSystem.get_default().load_from_desktop_file('gnome-network-scheme.desktop');
- } catch(e) {
- try {
- networkApp = Shell.AppSystem.get_default().load_from_desktop_file('network-scheme.desktop');
- } catch(e) {
- log("Cannot create \"Network\" item, .desktop file not found or corrupt.");
- }
- }
-
- if (networkApp != null) {
- let network = new PlaceDisplay(networkApp.get_name(),
- function() {
- return networkApp.create_icon_texture(PLACES_ICON_SIZE);
- },
- function () {
- networkApp.launch();
- });
- this._actionsBox.append(network.actor, Big.BoxPackFlags.NONE);
- }
-
- let connect = new PlaceDisplay(_("Connect to..."),
- function () {
- return Shell.TextureCache.get_default().load_icon_name("applications-internet", PLACES_ICON_SIZE);
- },
- function () {
- new Shell.Process({ args: ['nautilus-connect-server'] }).run();
- });
- this._actionsBox.append(connect.actor, Big.BoxPackFlags.NONE);
-
- this._bookmarksPath = GLib.build_filenamev([GLib.get_home_dir(), ".gtk-bookmarks"]);
- this._bookmarksFile = Gio.file_new_for_path(this._bookmarksPath);
- let monitor = this._bookmarksFile.monitor_file(Gio.FileMonitorFlags.NONE, null);
- this._bookmarkTimeoutId = 0;
- monitor.connect('changed', Lang.bind(this, function () {
- if (this._bookmarkTimeoutId > 0)
- return;
- /* Defensive event compression */
- this._bookmarkTimeoutId = Mainloop.timeout_add(100, Lang.bind(this, function () {
- this._bookmarkTimeoutId = 0;
- this._reloadBookmarks();
- return false;
- }));
- }));
-
- this._reloadBookmarks();
- },
-
- _reloadBookmarks: function() {
-
- this._dirsBox.remove_all();
-
- if (!GLib.file_test(this._bookmarksPath, GLib.FileTest.EXISTS))
- return;
-
- let [success, bookmarksContent, len] = GLib.file_get_contents(this._bookmarksPath);
-
- if (!success)
- return;
-
- let bookmarks = bookmarksContent.split('\n');
-
- let bookmarksToLabel = {};
- let bookmarksOrder = [];
- for (let i = 0; i < bookmarks.length; i++) {
- let bookmarkLine = bookmarks[i];
- let components = bookmarkLine.split(' ');
- let bookmark = components[0];
- if (bookmark in bookmarksToLabel)
- continue;
- let label = null;
- if (components.length > 1)
- label = components.slice(1).join(' ');
- bookmarksToLabel[bookmark] = label;
- bookmarksOrder.push(bookmark);
- }
-
- for (let i = 0; i < bookmarksOrder.length; i++) {
- let bookmark = bookmarksOrder[i];
- let label = bookmarksToLabel[bookmark];
- let file = Gio.file_new_for_uri(bookmark);
- if (!file.query_exists(null))
- continue;
- if (label == null)
- label = Shell.util_get_label_for_uri(bookmark);
- if (label == null)
- continue;
- let icon = Shell.util_get_icon_for_uri(bookmark);
-
- let item = new PlaceDisplay(label,
- function() {
- return Shell.TextureCache.get_default().load_gicon(icon, PLACES_ICON_SIZE);
- },
- function() {
- Gio.app_info_launch_default_for_uri(bookmark, Main.createAppLaunchContext());
- });
- this._dirsBox.append(item.actor, Big.BoxPackFlags.NONE);
- }
- },
-
- _updateDevices: function() {
- this._devBox.remove_all();
-
- /* first go through all connected drives */
- let drives = this._volumeMonitor.get_connected_drives();
- for (let i = 0; i < drives.length; i++) {
- let volumes = drives[i].get_volumes();
- for(let j = 0; j < volumes.length; j++) {
- let mount = volumes[j].get_mount();
- if(mount != null) {
- this._addMount(mount);
- }
- }
- }
-
- /* add all volumes that is not associated with a drive */
- let volumes = this._volumeMonitor.get_volumes();
- for(let i = 0; i < volumes.length; i++) {
- if(volumes[i].get_drive() != null)
- continue;
-
- let mount = volumes[i].get_mount();
- if(mount != null) {
- this._addMount(mount);
- }
- }
-
- /* add mounts that have no volume (/etc/mtab mounts, ftp, sftp,...) */
- let mounts = this._volumeMonitor.get_mounts();
- for(let i = 0; i < mounts.length; i++) {
- if(mounts[i].is_shadowed())
- continue;
-
- if(mounts[i].get_volume())
- continue;
-
- this._addMount(mounts[i]);
- }
- },
-
- _addMount: function(mount) {
- let mountLabel = mount.get_name();
- let mountIcon = mount.get_icon();
- let root = mount.get_root();
- let mountUri = root.get_uri();
- let devItem = new PlaceDisplay(mountLabel,
- function() {
- return Shell.TextureCache.get_default().load_gicon(mountIcon, PLACES_ICON_SIZE);
- },
- function() {
- Gio.app_info_launch_default_for_uri(mountUri, Main.createAppLaunchContext());
- });
- this._devBox.append(devItem.actor, Big.BoxPackFlags.NONE);
- },
-
- _updateDesktopMenuVisibility: function() {
- let gconf = Shell.GConf.get_default();
- let desktopIsHome = gconf.get_boolean(DESKTOP_IS_HOME_KEY);
- if (desktopIsHome)
- this._desktopMenu.actor.hide();
- else
- this._desktopMenu.actor.show();
- }
-};
-Signals.addSignalMethods(Places.prototype);
diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js
index 1d998efff..8ff743ecc 100644
--- a/js/ui/shellDBus.js
+++ b/js/ui/shellDBus.js
@@ -48,6 +48,9 @@ GnomeShell.prototype = {
let success;
try {
returnValue = JSON.stringify(eval(code));
+ // A hack; DBus doesn't have null/undefined
+ if (returnValue == undefined)
+ returnValue = "";
success = true;
} catch (e) {
returnValue = JSON.stringify(e);
diff --git a/js/ui/statusMenu.js b/js/ui/statusMenu.js
new file mode 100644
index 000000000..3486ca0bc
--- /dev/null
+++ b/js/ui/statusMenu.js
@@ -0,0 +1,297 @@
+/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
+
+const DBus = imports.dbus;
+const Gdm = imports.gi.Gdm;
+const GLib = imports.gi.GLib;
+const Gtk = imports.gi.Gtk;
+const Lang = imports.lang;
+const Shell = imports.gi.Shell;
+const St = imports.gi.St;
+const Signals = imports.signals;
+const Gettext = imports.gettext.domain('gnome-shell');
+const _ = Gettext.gettext;
+
+const Panel = imports.ui.panel;
+
+// Adapted from gdm/gui/user-switch-applet/applet.c
+//
+// Copyright (C) 2004-2005 James M. Cape .
+// Copyright (C) 2008,2009 Red Hat, Inc.
+
+const SIDEBAR_VISIBLE_KEY = 'sidebar/visible';
+
+function StatusMenu() {
+ this._init();
+}
+
+StatusMenu.prototype = {
+ _init: function() {
+ this._gdm = Gdm.UserManager.ref_default();
+ this._user = this._gdm.get_user(GLib.get_user_name());
+ this._presence = new GnomeSessionPresence();
+
+ this.actor = new St.BoxLayout({ name: 'StatusMenu' });
+ this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
+
+ this._iconBox = new St.Bin();
+ this.actor.add(this._iconBox, { y_align: St.Align.MIDDLE });
+
+ let textureCache = Shell.TextureCache.get_default();
+ // FIXME: these icons are all wrong (likewise in createSubMenu)
+ this._availableIcon = textureCache.load_icon_name('gtk-yes', 16);
+ this._busyIcon = textureCache.load_icon_name('gtk-no', 16);
+ this._invisibleIcon = textureCache.load_icon_name('gtk-close', 16);
+ this._idleIcon = textureCache.load_icon_name('gtk-media-pause', 16);
+
+ this._presence.connect('StatusChanged', Lang.bind(this, this._updatePresenceIcon));
+ this._presence.getStatus(Lang.bind(this, this._updatePresenceIcon));
+
+ this._name = new St.Label({ text: this._user.get_real_name() });
+ this.actor.add(this._name, { expand: true, y_align: St.Align.MIDDLE });
+ this._userNameChangedId = this._user.connect('notify::display-name', Lang.bind(this, this._updateUserName));
+
+ this._createSubMenu();
+ this._gdm.connect('users-loaded', Lang.bind(this, this._updateSwitchUser));
+ this._gdm.connect('user-added', Lang.bind(this, this._updateSwitchUser));
+ this._gdm.connect('user-removed', Lang.bind(this, this._updateSwitchUser));
+ },
+
+ _onDestroy: function() {
+ this._user.disconnect(this._userNameChangedId);
+ },
+
+ _updateUserName: function() {
+ this._name.set_text(this._user.get_real_name());
+ },
+
+ _updateSwitchUser: function() {
+ let users = this._gdm.list_users();
+ if (users.length > 1)
+ this._loginScreenItem.show();
+ else
+ this._loginScreenItem.hide();
+ },
+
+ _updatePresenceIcon: function(presence, status) {
+ if (status == GnomeSessionPresenceStatus.AVAILABLE)
+ this._iconBox.child = this._availableIcon;
+ else if (status == GnomeSessionPresenceStatus.BUSY)
+ this._iconBox.child = this._busyIcon;
+ else if (status == GnomeSessionPresenceStatus.INVISIBLE)
+ this._iconBox.child = this._invisibleIcon;
+ else
+ this._iconBox.child = this._idleIcon;
+ },
+
+ // The menu
+
+ _createImageMenuItem: function(label, iconName, forceIcon) {
+ let image = new Gtk.Image();
+ let item = new Gtk.ImageMenuItem({ label: label,
+ image: image,
+ always_show_image: forceIcon == true });
+ item.connect('style-set', Lang.bind(this,
+ function() {
+ image.set_from_icon_name(iconName, Gtk.IconSize.MENU);
+ }));
+
+ return item;
+ },
+
+ _createSubMenu: function() {
+ this._menu = new Gtk.Menu();
+ this._menu.connect('deactivate', Lang.bind(this, function() { this.emit('deactivated'); }));
+
+ let item;
+
+ item = this._createImageMenuItem(_('Available'), 'gtk-yes', true);
+ item.connect('activate', Lang.bind(this, this._setPresenceStatus, GnomeSessionPresenceStatus.AVAILABLE));
+ this._menu.append(item);
+ item.show();
+
+ item = this._createImageMenuItem(_('Busy'), 'gtk-no', true);
+ item.connect('activate', Lang.bind(this, this._setPresenceStatus, GnomeSessionPresenceStatus.BUSY));
+ this._menu.append(item);
+ item.show();
+
+ item = this._createImageMenuItem(_('Invisible'), 'gtk-close', true);
+ item.connect('activate', Lang.bind(this, this._setPresenceStatus, GnomeSessionPresenceStatus.INVISIBLE));
+ this._menu.append(item);
+ item.show();
+
+ item = new Gtk.SeparatorMenuItem();
+ this._menu.append(item);
+ item.show();
+
+ item = this._createImageMenuItem(_('Account Information...'), 'user-info');
+ item.connect('activate', Lang.bind(this, this._onAccountInformationActivate));
+ this._menu.append(item);
+ item.show();
+
+ let gconf = Shell.GConf.get_default();
+ item = new Gtk.CheckMenuItem({ label: _('Sidebar'),
+ active: gconf.get_boolean(SIDEBAR_VISIBLE_KEY) });
+ item.connect('activate', Lang.bind(this,
+ function() {
+ gconf.set_boolean(SIDEBAR_VISIBLE_KEY, this._sidebarItem.active);
+ }));
+ this._menu.append(item);
+ item.show();
+ this._sidebarItem = item;
+
+ item = this._createImageMenuItem(_('System Preferences...'), 'preferences-desktop');
+ item.connect('activate', Lang.bind(this, this._onPreferencesActivate));
+ this._menu.append(item);
+ item.show();
+
+ item = new Gtk.SeparatorMenuItem();
+ this._menu.append(item);
+ item.show();
+
+ item = this._createImageMenuItem(_('Lock Screen'), 'system-lock-screen');
+ item.connect('activate', Lang.bind(this, this._onLockScreenActivate));
+ this._menu.append(item);
+ item.show();
+
+ item = this._createImageMenuItem(_('Switch User'), 'system-users');
+ item.connect('activate', Lang.bind(this, this._onLoginScreenActivate));
+ this._menu.append(item);
+ item.show();
+ this._loginScreenItem = item;
+
+ item = this._createImageMenuItem(_('Log Out...'), 'system-log-out');
+ item.connect('activate', Lang.bind(this, this._onQuitSessionActivate));
+ this._menu.append(item);
+ item.show();
+
+ item = this._createImageMenuItem(_('Shut Down...'), 'system-shutdown');
+ item.connect('activate', Lang.bind(this, this._onShutDownActivate));
+ this._menu.append(item);
+ item.show();
+ },
+
+ _setPresenceStatus: function(item, status) {
+ this._presence.setStatus(status);
+ },
+
+ _onAccountInformationActivate: function() {
+ this._spawn(['gnome-about-me']);
+ },
+
+ _onPreferencesActivate: function() {
+ this._spawn(['gnome-control-center']);
+ },
+
+ _onLockScreenActivate: function() {
+ this._spawn(['gnome-screensaver-command', '--lock']);
+ },
+
+ _onLoginScreenActivate: function() {
+ this._gdm.goto_login_session();
+ this._onLockScreenActivate();
+ },
+
+ _onQuitSessionActivate: function() {
+ this._spawn(['gnome-session-save', '--logout-dialog']);
+ },
+
+ _onShutDownActivate: function() {
+ this._spawn(['gnome-session-save', '--shutdown-dialog']);
+ },
+
+ _spawn: function(args) {
+ // FIXME: once Shell.Process gets support for signalling
+ // errors we should pop up an error dialog or something here
+ // on failure
+ let p = new Shell.Process({'args' : args});
+ p.run();
+ },
+
+ // shell_status_menu_toggle:
+ // @event: event causing the toggle
+ //
+ // If the menu is not currently up, pops it up. Otherwise, hides it.
+ // Popping up may fail if another grab is already active; check with
+ // isActive().
+ toggle: function(event) {
+ if (this._menu.visible)
+ this._menu.popdown();
+ else {
+ // We don't want to overgrab a Mutter grab with the grab
+ // that GTK+ uses on menus.
+ if (global.display_is_grabbed())
+ return;
+
+ let [menuWidth, menuHeight] = this._menu.get_size_request ();
+
+ let panel;
+ for (panel = this.actor; panel; panel = panel.get_parent()) {
+ if (panel._delegate instanceof Panel.Panel)
+ break;
+ }
+
+ let [panelX, panelY] = panel.get_transformed_position();
+ let [panelWidth, panelHeight] = panel.get_transformed_size();
+
+ let menuX = Math.round(panelX + panelWidth - menuWidth);
+ let menuY = Math.round(panelY + panelHeight);
+
+ Shell.popup_menu(this._menu, event.get_button(), event.get_time(),
+ menuX, menuY);
+ }
+ },
+
+ // isActive:
+ //
+ // Gets whether the menu is currently popped up
+ //
+ // Return value: %true if the menu is currently popped up
+ isActive: function() {
+ return this._menu.visible;
+ }
+};
+Signals.addSignalMethods(StatusMenu.prototype);
+
+
+const GnomeSessionPresenceIface = {
+ name: 'org.gnome.SessionManager.Presence',
+ methods: [{ name: 'SetStatus',
+ inSignature: 'u' }],
+ properties: [{ name: 'status',
+ signature: 'u',
+ access: 'readwrite' }],
+ signals: [{ name: 'StatusChanged',
+ inSignature: 'u' }]
+};
+
+const GnomeSessionPresenceStatus = {
+ AVAILABLE: 0,
+ INVISIBLE: 1,
+ BUSY: 2,
+ IDLE: 3
+};
+
+function GnomeSessionPresence() {
+ this._init();
+}
+
+GnomeSessionPresence.prototype = {
+ _init: function() {
+ DBus.session.proxifyObject(this, 'org.gnome.SessionManager', '/org/gnome/SessionManager/Presence', this);
+ this.connect('StatusChanged', Lang.bind(this, function (proxy, status) { this.status = status; }));
+ },
+
+ getStatus: function(callback) {
+ this.GetRemote('status', Lang.bind(this,
+ function(status, ex) {
+ if (!ex)
+ callback(this, status);
+ }));
+ },
+
+ setStatus: function(status) {
+ this.SetStatusRemote(status);
+ }
+};
+DBus.proxifyPrototype(GnomeSessionPresence.prototype, GnomeSessionPresenceIface);
+
diff --git a/js/ui/workspaces.js b/js/ui/workspaces.js
index 1cde8acce..8e4a60d97 100644
--- a/js/ui/workspaces.js
+++ b/js/ui/workspaces.js
@@ -575,6 +575,9 @@ Workspace.prototype = {
this._lightbox.destroy();
this._lightbox = null;
}
+ if (this._frame) {
+ this._frame.set_opacity(showLightbox ? 150 : 255);
+ }
},
/**
diff --git a/po/POTFILES.in b/po/POTFILES.in
index a44a0f173..6e72d3962 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -4,7 +4,7 @@ js/ui/appIcon.js
js/ui/dash.js
js/ui/overview.js
js/ui/panel.js
-js/ui/places.js
+js/ui/placeDisplay.js
js/ui/runDialog.js
js/ui/widget.js
src/gdmuser/gdm-user.c
diff --git a/po/ar.po b/po/ar.po
index b593e3e3c..06cf8851a 100644
--- a/po/ar.po
+++ b/po/ar.po
@@ -6,8 +6,8 @@ msgid ""
msgstr ""
"Project-Id-Version: HEAD\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2009-10-13 15:24+0200\n"
-"PO-Revision-Date: 2009-10-13 15:23+0300\n"
+"POT-Creation-Date: 2009-11-08 20:55+0200\n"
+"PO-Revision-Date: 2009-11-08 20:55+0300\n"
"Last-Translator: Khaled Hosny \n"
"Language-Team: Arabic \n"
"MIME-Version: 1.0\n"
@@ -16,7 +16,7 @@ msgstr ""
"Language: ar\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
"&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
-"X-Generator: Virtaal 0.4.0\n"
+"X-Generator: Virtaal 0.4.1\n"
#: ../data/gnome-shell.desktop.in.in.h:1
msgid "GNOME Shell"
@@ -26,68 +26,72 @@ msgstr "صدفة جنوم"
msgid "Window management and application launching"
msgstr "إدارة النوافذ وإطلاق التطبيقات"
-#: ../js/ui/appDisplay.js:335
+#: ../js/ui/appDisplay.js:332
msgid "Frequent"
msgstr "متكرر"
-#: ../js/ui/appIcon.js:462
+#: ../js/ui/appDisplay.js:867
+msgid "Drag here to add favorites"
+msgstr "اسحب إلى هنا ليضاف إلى المفضّلة"
+
+#: ../js/ui/appIcon.js:426
msgid "New Window"
msgstr "نافذة جديدة"
-#: ../js/ui/appIcon.js:475
+#: ../js/ui/appIcon.js:430
msgid "Remove from Favorites"
msgstr "أزِل من المفضّلة"
-#: ../js/ui/appIcon.js:476
+#: ../js/ui/appIcon.js:431
msgid "Add to Favorites"
msgstr "أضِف إلى المفضّلة"
-#: ../js/ui/dash.js:283
+#: ../js/ui/dash.js:267
msgid "Find..."
msgstr "ابحث..."
-#: ../js/ui/dash.js:400
+#: ../js/ui/dash.js:376
msgid "More"
msgstr "المزيد"
-#: ../js/ui/dash.js:543
+#: ../js/ui/dash.js:532
msgid "(see all)"
msgstr "(انظر الكل)"
#. **** Applications ****
-#: ../js/ui/dash.js:763 ../js/ui/dash.js:825
+#: ../js/ui/dash.js:711 ../js/ui/dash.js:773
msgid "APPLICATIONS"
msgstr "التطبيقات"
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
-#: ../js/ui/dash.js:783
+#: ../js/ui/dash.js:731
msgid "PLACES"
msgstr "الأماكن"
#. **** Documents ****
-#: ../js/ui/dash.js:790 ../js/ui/dash.js:835
+#: ../js/ui/dash.js:738 ../js/ui/dash.js:783
msgid "RECENT DOCUMENTS"
msgstr "المستندات الحديثة"
#. **** Search Results ****
-#: ../js/ui/dash.js:815 ../js/ui/dash.js:955
+#: ../js/ui/dash.js:763 ../js/ui/dash.js:947
msgid "SEARCH RESULTS"
msgstr "نتائج البحث"
-#: ../js/ui/dash.js:830
+#: ../js/ui/dash.js:778
msgid "PREFERENCES"
msgstr "التفضيلات"
#. Button on the left side of the panel.
#. Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview".
-#: ../js/ui/panel.js:272
+#: ../js/ui/panel.js:274
msgid "Activities"
msgstr "الأنشطة"
#. Translators: This is a time format.
-#: ../js/ui/panel.js:464
+#: ../js/ui/panel.js:491
msgid "%a %l:%M %p"
msgstr "%A %Ol:%OM %p"
@@ -105,23 +109,23 @@ msgid "Execution of '%s' failed:"
msgstr "فشل تنفيذ '%s':"
#. Translators: This is a time format.
-#: ../js/ui/widget.js:162
+#: ../js/ui/widget.js:163
msgid "%H:%M"
msgstr "%OH:%OM"
-#: ../js/ui/widget.js:316
+#: ../js/ui/widget.js:317
msgid "Applications"
msgstr "التطبيقات"
-#: ../js/ui/widget.js:341
+#: ../js/ui/widget.js:339
msgid "Recent Documents"
msgstr "المستندات الحديثة"
-#: ../src/shell-global.c:812
+#: ../src/shell-global.c:821
msgid "Less than a minute ago"
msgstr "منذ أقل من دقيقة"
-#: ../src/shell-global.c:815
+#: ../src/shell-global.c:824
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
@@ -132,7 +136,7 @@ msgstr[3] "منذ %d دقائق"
msgstr[4] "منذ %d دقيقة"
msgstr[5] "منذ %d دقيقة"
-#: ../src/shell-global.c:818
+#: ../src/shell-global.c:827
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
@@ -143,7 +147,7 @@ msgstr[3] "منذ %d ساعات"
msgstr[4] "منذ %d ساعة"
msgstr[5] "منذ %d ساعة"
-#: ../src/shell-global.c:821
+#: ../src/shell-global.c:830
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
@@ -154,7 +158,7 @@ msgstr[3] "منذ %d أيام"
msgstr[4] "منذ %d يوما"
msgstr[5] "منذ %d يوم"
-#: ../src/shell-global.c:824
+#: ../src/shell-global.c:833
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
diff --git a/po/cs.po b/po/cs.po
index d5b59f74a..76cd5e5a4 100644
--- a/po/cs.po
+++ b/po/cs.po
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gnome-shell\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2009-10-10 19:02+0200\n"
-"PO-Revision-Date: 2009-10-10 19:02+0200\n"
+"POT-Creation-Date: 2009-11-05 18:03+0100\n"
+"PO-Revision-Date: 2009-11-05 18:03+0100\n"
"Last-Translator: Petr Kovar \n"
"Language-Team: Czech \n"
"MIME-Version: 1.0\n"
@@ -25,68 +25,72 @@ msgstr "Prostředí GNOME Shell"
msgid "Window management and application launching"
msgstr "Správa oken a spouštění aplikací"
-#: ../js/ui/appDisplay.js:335
+#: ../js/ui/appDisplay.js:332
msgid "Frequent"
msgstr "Časté"
-#: ../js/ui/appIcon.js:462
+#: ../js/ui/appDisplay.js:867
+msgid "Drag here to add favorites"
+msgstr "Oblíbené přidáte přetažením sem"
+
+#: ../js/ui/appIcon.js:426
msgid "New Window"
msgstr "Nové okno"
-#: ../js/ui/appIcon.js:475
+#: ../js/ui/appIcon.js:430
msgid "Remove from Favorites"
msgstr "Odstranit z oblíbených"
-#: ../js/ui/appIcon.js:476
+#: ../js/ui/appIcon.js:431
msgid "Add to Favorites"
msgstr "Přidat mezi oblíbené"
-#: ../js/ui/dash.js:283
+#: ../js/ui/dash.js:267
msgid "Find..."
msgstr "Najít..."
-#: ../js/ui/dash.js:400
+#: ../js/ui/dash.js:376
msgid "More"
msgstr "Více"
-#: ../js/ui/dash.js:543
+#: ../js/ui/dash.js:532
msgid "(see all)"
msgstr "(zobrazit vše)"
#. **** Applications ****
-#: ../js/ui/dash.js:763 ../js/ui/dash.js:825
+#: ../js/ui/dash.js:711 ../js/ui/dash.js:773
msgid "APPLICATIONS"
msgstr "APLIKACE"
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
-#: ../js/ui/dash.js:783
+#: ../js/ui/dash.js:731
msgid "PLACES"
msgstr "MÍSTA"
#. **** Documents ****
-#: ../js/ui/dash.js:790 ../js/ui/dash.js:835
+#: ../js/ui/dash.js:738 ../js/ui/dash.js:783
msgid "RECENT DOCUMENTS"
msgstr "NEDÁVNÉ DOKUMENTY"
#. **** Search Results ****
-#: ../js/ui/dash.js:815 ../js/ui/dash.js:955
+#: ../js/ui/dash.js:763 ../js/ui/dash.js:947
msgid "SEARCH RESULTS"
msgstr "VÝSLEDKY HLEDÁNÍ"
-#: ../js/ui/dash.js:830
+#: ../js/ui/dash.js:778
msgid "PREFERENCES"
msgstr "PŘEDVOLBY"
#. Button on the left side of the panel.
#. Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview".
-#: ../js/ui/panel.js:272
+#: ../js/ui/panel.js:274
msgid "Activities"
msgstr "Činnosti"
#. Translators: This is a time format.
-#: ../js/ui/panel.js:464
+#: ../js/ui/panel.js:491
msgid "%a %l:%M %p"
msgstr "%a, %H:%M"
@@ -104,23 +108,23 @@ msgid "Execution of '%s' failed:"
msgstr "Vykonání \"%s\" selhalo:"
#. Translators: This is a time format.
-#: ../js/ui/widget.js:162
+#: ../js/ui/widget.js:163
msgid "%H:%M"
msgstr "%H:%M"
-#: ../js/ui/widget.js:316
+#: ../js/ui/widget.js:317
msgid "Applications"
msgstr "Aplikace"
-#: ../js/ui/widget.js:341
+#: ../js/ui/widget.js:339
msgid "Recent Documents"
msgstr "Nedávné dokumenty"
-#: ../src/shell-global.c:812
+#: ../src/shell-global.c:821
msgid "Less than a minute ago"
msgstr "Před méně než minutou"
-#: ../src/shell-global.c:815
+#: ../src/shell-global.c:824
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
@@ -128,7 +132,7 @@ msgstr[0] "Před %d minutou"
msgstr[1] "Před %d minutami"
msgstr[2] "Před %d minutami"
-#: ../src/shell-global.c:818
+#: ../src/shell-global.c:827
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
@@ -136,7 +140,7 @@ msgstr[0] "Před %d hodinou"
msgstr[1] "Před %d hodinami"
msgstr[2] "Před %d hodinami"
-#: ../src/shell-global.c:821
+#: ../src/shell-global.c:830
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
@@ -144,7 +148,7 @@ msgstr[0] "Před %d dnem"
msgstr[1] "Před %d dny"
msgstr[2] "Před %d dny"
-#: ../src/shell-global.c:824
+#: ../src/shell-global.c:833
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
diff --git a/po/fi.po b/po/fi.po
new file mode 100644
index 000000000..9fb695280
--- /dev/null
+++ b/po/fi.po
@@ -0,0 +1,226 @@
+# gnome-shell Finnish translation
+# Copyright (C) 2009 Timo Jyrinki
+# This file is distributed under the same license as the gnome-shell package.
+# Timo Jyrinki , 2009.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gnome-shell\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-11-04 11:16+0200\n"
+"PO-Revision-Date: 2009-11-04 11:16+0200\n"
+"Last-Translator: Timo Jyrinki \n"
+"Language-Team: Finnish \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+
+#: ../data/gnome-shell.desktop.in.in.h:1
+msgid "GNOME Shell"
+msgstr ""
+
+#: ../data/gnome-shell.desktop.in.in.h:2
+msgid "Window management and application launching"
+msgstr "Ikkunanhallinta ja sovelluksien käynnistäminen"
+
+#: ../js/ui/appDisplay.js:332
+msgid "Frequent"
+msgstr "Usein käytetyt"
+
+#: ../js/ui/appDisplay.js:867
+msgid "Drag here to add favorites"
+msgstr "Raahaa tähän lisätäksesi suosikkeihin"
+
+#: ../js/ui/appIcon.js:426
+msgid "New Window"
+msgstr "Uusi ikkuna"
+
+#: ../js/ui/appIcon.js:430
+msgid "Remove from Favorites"
+msgstr "Poista suosikeista"
+
+#: ../js/ui/appIcon.js:431
+msgid "Add to Favorites"
+msgstr "Lisää suosikkeihin"
+
+#: ../js/ui/dash.js:283
+msgid "Find..."
+msgstr "Etsi..."
+
+#: ../js/ui/dash.js:400
+msgid "More"
+msgstr "Lisää"
+
+#: ../js/ui/dash.js:543
+msgid "(see all)"
+msgstr "(näytä kaikki)"
+
+#. **** Applications ****
+#: ../js/ui/dash.js:725 ../js/ui/dash.js:787
+msgid "APPLICATIONS"
+msgstr "SOVELLUKSET"
+
+#. **** Places ****
+#. Translators: This is in the sense of locations for documents,
+#. network locations, etc.
+#: ../js/ui/dash.js:745
+msgid "PLACES"
+msgstr "SIJAINNIT"
+
+#. **** Documents ****
+#: ../js/ui/dash.js:752 ../js/ui/dash.js:797
+msgid "RECENT DOCUMENTS"
+msgstr "VIIMEISIMMÄT ASIAKIRJAT"
+
+#. **** Search Results ****
+#: ../js/ui/dash.js:777 ../js/ui/dash.js:961
+msgid "SEARCH RESULTS"
+msgstr "HAKUTULOKSET"
+
+#: ../js/ui/dash.js:792
+msgid "PREFERENCES"
+msgstr "ASETUKSET"
+
+#. Button on the left side of the panel.
+#. Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview".
+#: ../js/ui/panel.js:274
+msgid "Activities"
+msgstr "Toiminnot"
+
+#. Translators: This is a time format.
+#: ../js/ui/panel.js:491
+msgid "%a %l:%M %p"
+msgstr "%a %I.%M"
+
+#: ../js/ui/places.js:178
+msgid "Connect to..."
+msgstr "Yhdistä..."
+
+#: ../js/ui/runDialog.js:96
+msgid "Please enter a command:"
+msgstr "Syötä komento:"
+
+#: ../js/ui/runDialog.js:173
+#, c-format
+msgid "Execution of '%s' failed:"
+msgstr ""
+
+#. Translators: This is a time format.
+#: ../js/ui/widget.js:163
+msgid "%H:%M"
+msgstr "%I.%M"
+
+#: ../js/ui/widget.js:317
+msgid "Applications"
+msgstr "Sovellukset"
+
+#: ../js/ui/widget.js:339
+msgid "Recent Documents"
+msgstr "Viimeisimmät asiakirjat"
+
+#: ../src/shell-global.c:821
+msgid "Less than a minute ago"
+msgstr "Alle minuutti sitten"
+
+#: ../src/shell-global.c:824
+#, c-format
+msgid "%d minute ago"
+msgid_plural "%d minutes ago"
+msgstr[0] "%d minuutti sitten"
+msgstr[1] "%d minuuttia sitten"
+
+#: ../src/shell-global.c:827
+#, c-format
+msgid "%d hour ago"
+msgid_plural "%d hours ago"
+msgstr[0] "%d tunti sitten"
+msgstr[1] "%d tuntia sitten"
+
+#: ../src/shell-global.c:830
+#, c-format
+msgid "%d day ago"
+msgid_plural "%d days ago"
+msgstr[0] "%d päivä sitten"
+msgstr[1] "%d päivää sitten"
+
+#: ../src/shell-global.c:833
+#, c-format
+msgid "%d week ago"
+msgid_plural "%d weeks ago"
+msgstr[0] "%d viikko sitten"
+msgstr[1] "%d viikkoa sitten"
+
+#: ../src/shell-status-menu.c:156
+msgid "Unknown"
+msgstr "Tuntematon"
+
+#: ../src/shell-status-menu.c:212
+#, c-format
+msgid "Can't lock screen: %s"
+msgstr "Näyttöä ei voi lukita: %s"
+
+#: ../src/shell-status-menu.c:227
+#, c-format
+msgid "Can't temporarily set screensaver to blank screen: %s"
+msgstr ""
+
+#: ../src/shell-status-menu.c:351
+#, c-format
+msgid "Can't logout: %s"
+msgstr ""
+
+#: ../src/shell-status-menu.c:492
+msgid "Account Information..."
+msgstr "Käyttäjätilin tiedot..."
+
+#: ../src/shell-status-menu.c:502
+msgid "Sidebar"
+msgstr "Sivupalkki"
+
+#: ../src/shell-status-menu.c:510
+msgid "System Preferences..."
+msgstr "Järjestelmän asetukset"
+
+#: ../src/shell-status-menu.c:525
+msgid "Lock Screen"
+msgstr "Lukitse näyttö"
+
+#: ../src/shell-status-menu.c:535
+msgid "Switch User"
+msgstr "Vaihda käyttäjää"
+
+#. Only show switch user if there are other users
+#. Log Out
+#: ../src/shell-status-menu.c:546
+msgid "Log Out..."
+msgstr "Kirjaudu ulos..."
+
+#. Shut down
+#: ../src/shell-status-menu.c:557
+msgid "Shut Down..."
+msgstr "Sammuta..."
+
+#: ../src/shell-uri-util.c:87
+msgid "Home Folder"
+msgstr "Kotikansio"
+
+#. Translators: this is the same string as the one found in
+#. * nautilus
+#: ../src/shell-uri-util.c:102
+msgid "File System"
+msgstr "Tiedostojärjestelmä"
+
+#: ../src/shell-uri-util.c:248
+msgid "Search"
+msgstr "Haku"
+
+#. Translators: the first string is the name of a gvfs
+#. * method, and the second string is a path. For
+#. * example, "Trash: some-directory". It means that the
+#. * directory called "some-directory" is in the trash.
+#.
+#: ../src/shell-uri-util.c:298
+#, c-format
+msgid "%1$s: %2$s"
+msgstr "%1$s: %2$s"
diff --git a/po/it.po b/po/it.po
index cdc36bb9f..ff145d7b7 100644
--- a/po/it.po
+++ b/po/it.po
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gnome-shell\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2009-10-10 12:20+0200\n"
-"PO-Revision-Date: 2009-10-10 12:39+0200\n"
+"POT-Creation-Date: 2009-11-03 22:26+0100\n"
+"PO-Revision-Date: 2009-11-03 22:28+0100\n"
"Last-Translator: Milo Casagrande \n"
"Language-Team: Italian \n"
"MIME-Version: 1.0\n"
@@ -24,19 +24,23 @@ msgstr "GNOME Shell"
msgid "Window management and application launching"
msgstr "Gestione finestre e avvio applicazioni"
-#: ../js/ui/appDisplay.js:335
+#: ../js/ui/appDisplay.js:332
msgid "Frequent"
msgstr "Frequente"
-#: ../js/ui/appIcon.js:462
+#: ../js/ui/appDisplay.js:867
+msgid "Drag here to add favorites"
+msgstr "Trascinare qui per aggiungere ai preferiti"
+
+#: ../js/ui/appIcon.js:426
msgid "New Window"
msgstr "Nuova finestra"
-#: ../js/ui/appIcon.js:475
+#: ../js/ui/appIcon.js:430
msgid "Remove from Favorites"
msgstr "Rimuovi dai preferiti"
-#: ../js/ui/appIcon.js:476
+#: ../js/ui/appIcon.js:431
msgid "Add to Favorites"
msgstr "Aggiungi ai preferiti"
@@ -53,40 +57,40 @@ msgid "(see all)"
msgstr "(vedi tutto)"
#. **** Applications ****
-#: ../js/ui/dash.js:763 ../js/ui/dash.js:825
+#: ../js/ui/dash.js:725 ../js/ui/dash.js:787
msgid "APPLICATIONS"
msgstr "Applicazioni"
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
-#: ../js/ui/dash.js:783
+#: ../js/ui/dash.js:745
msgid "PLACES"
msgstr "Risorse"
#. **** Documents ****
-#: ../js/ui/dash.js:790 ../js/ui/dash.js:835
+#: ../js/ui/dash.js:752 ../js/ui/dash.js:797
msgid "RECENT DOCUMENTS"
msgstr "Documenti recenti"
#. **** Search Results ****
-#: ../js/ui/dash.js:815 ../js/ui/dash.js:955
+#: ../js/ui/dash.js:777 ../js/ui/dash.js:961
msgid "SEARCH RESULTS"
msgstr "Risultati ricerca"
-#: ../js/ui/dash.js:830
+#: ../js/ui/dash.js:792
msgid "PREFERENCES"
msgstr "Preferenze"
#. Button on the left side of the panel.
#. Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview".
-#: ../js/ui/panel.js:272
+#: ../js/ui/panel.js:274
msgid "Activities"
msgstr "Attività"
# (ndt) proviamo col k, se non funge, sappiamo il perché...
#. Translators: This is a time format.
-#: ../js/ui/panel.js:464
+#: ../js/ui/panel.js:491
msgid "%a %l:%M %p"
msgstr "%a %k.%M"
@@ -104,44 +108,44 @@ msgid "Execution of '%s' failed:"
msgstr "Esecuzione di «%s» non riuscita:"
#. Translators: This is a time format.
-#: ../js/ui/widget.js:162
+#: ../js/ui/widget.js:163
msgid "%H:%M"
msgstr "%k.%M"
-#: ../js/ui/widget.js:316
+#: ../js/ui/widget.js:317
msgid "Applications"
msgstr "Applicazioni"
-#: ../js/ui/widget.js:341
+#: ../js/ui/widget.js:339
msgid "Recent Documents"
msgstr "Documenti recenti"
-#: ../src/shell-global.c:812
+#: ../src/shell-global.c:821
msgid "Less than a minute ago"
msgstr "Meno di un minuto fa"
-#: ../src/shell-global.c:815
+#: ../src/shell-global.c:824
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "%d minuto fa"
msgstr[1] "%d minuti fa"
-#: ../src/shell-global.c:818
+#: ../src/shell-global.c:827
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "%d ora fa"
msgstr[1] "%d ore fa"
-#: ../src/shell-global.c:821
+#: ../src/shell-global.c:830
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "%d giorno fa"
msgstr[1] "%d giorni fa"
-#: ../src/shell-global.c:824
+#: ../src/shell-global.c:833
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
@@ -225,18 +229,3 @@ msgstr "Cerca"
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"
-
-#~ msgid "Browse"
-#~ msgstr "Esplora"
-
-# (ndt) è da valutare se è troppo lunga, è in una casella di ricerca
-#~ msgid "Find apps or documents"
-#~ msgstr "Trova programmi e documenti"
-
-# (ndt) no idea...
-#~ msgid "Manager"
-#~ msgstr "Manager"
-
-# (ndt) no idea...
-#~ msgid "The user manager object this user is controlled by."
-#~ msgstr "L'oggetto user manager che controlla questo utente."
diff --git a/po/sl.po b/po/sl.po
index 6ae049c58..e55ddadff 100644
--- a/po/sl.po
+++ b/po/sl.po
@@ -6,8 +6,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gnome-shell master\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell&component=general\n"
-"POT-Creation-Date: 2009-10-23 17:29+0000\n"
-"PO-Revision-Date: 2009-10-26 07:29+0100\n"
+"POT-Creation-Date: 2009-11-12 21:33+0000\n"
+"PO-Revision-Date: 2009-11-14 10:19+0100\n"
"Last-Translator: Matej Urbančič \n"
"Language-Team: Slovenian GNOME Translation Team \n"
"MIME-Version: 1.0\n"
@@ -27,60 +27,53 @@ msgstr "Gnome lupina"
msgid "Window management and application launching"
msgstr "Upravljanje oken in zaganjanje programov"
-#: ../js/ui/appDisplay.js:332
-msgid "Frequent"
-msgstr "Pogosto"
+#: ../js/ui/appDisplay.js:696
+msgid "Drag here to add favorites"
+msgstr "S potegom na to mesto se izbor doda med priljubljene"
-#: ../js/ui/appIcon.js:426
+#: ../js/ui/appIcon.js:425
msgid "New Window"
msgstr "Novo okno"
-#: ../js/ui/appIcon.js:430
+#: ../js/ui/appIcon.js:429
msgid "Remove from Favorites"
msgstr "Odstrani iz priljubljenih"
-#: ../js/ui/appIcon.js:431
+#: ../js/ui/appIcon.js:430
msgid "Add to Favorites"
msgstr "Dodaj med priljubljene"
-#: ../js/ui/dash.js:283
+#: ../js/ui/dash.js:237
msgid "Find..."
msgstr "Poišči ..."
-#: ../js/ui/dash.js:400
-msgid "More"
-msgstr "Več"
-
-#: ../js/ui/dash.js:543
-msgid "(see all)"
-msgstr "(poglej vse)"
-
#. **** Applications ****
-#: ../js/ui/dash.js:725
-#: ../js/ui/dash.js:787
+#: ../js/ui/dash.js:656
+#: ../js/ui/dash.js:718
msgid "APPLICATIONS"
msgstr "Programi"
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
-#: ../js/ui/dash.js:745
+#: ../js/ui/dash.js:676
+#: ../js/ui/dash.js:733
msgid "PLACES"
msgstr "Mesta"
#. **** Documents ****
-#: ../js/ui/dash.js:752
-#: ../js/ui/dash.js:797
+#: ../js/ui/dash.js:683
+#: ../js/ui/dash.js:728
msgid "RECENT DOCUMENTS"
msgstr "Nedavni dokumenti"
#. **** Search Results ****
-#: ../js/ui/dash.js:777
-#: ../js/ui/dash.js:961
+#: ../js/ui/dash.js:708
+#: ../js/ui/dash.js:898
msgid "SEARCH RESULTS"
msgstr "Rezultati iskanja"
-#: ../js/ui/dash.js:792
+#: ../js/ui/dash.js:723
msgid "PREFERENCES"
msgstr "Lastnosti"
@@ -95,13 +88,13 @@ msgstr "Dejavnosti"
msgid "%a %l:%M %p"
msgstr "%a, %H:%M"
-#: ../js/ui/places.js:178
+#: ../js/ui/placeDisplay.js:84
msgid "Connect to..."
msgstr "Povezava z ..."
#: ../js/ui/runDialog.js:96
msgid "Please enter a command:"
-msgstr "Prosim, vnesite ukaz:"
+msgstr "Vnos ukaza:"
#: ../js/ui/runDialog.js:173
#, c-format
@@ -121,11 +114,11 @@ msgstr "Programi"
msgid "Recent Documents"
msgstr "Nedavni dokumenti"
-#: ../src/shell-global.c:812
+#: ../src/shell-global.c:821
msgid "Less than a minute ago"
msgstr "Pred manj kot eno minuto"
-#: ../src/shell-global.c:815
+#: ../src/shell-global.c:824
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
@@ -134,7 +127,7 @@ msgstr[1] "Pred %d minuto"
msgstr[2] "Pred %d minutama"
msgstr[3] "Pred %d minutami"
-#: ../src/shell-global.c:818
+#: ../src/shell-global.c:827
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
@@ -143,7 +136,7 @@ msgstr[1] "Pred %d uro"
msgstr[2] "Pred %d urama"
msgstr[3] "Pred %d urami"
-#: ../src/shell-global.c:821
+#: ../src/shell-global.c:830
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
@@ -152,7 +145,7 @@ msgstr[1] "Pred %d dnevom"
msgstr[2] "Pred %d dnevoma"
msgstr[3] "Pred %d dnevi"
-#: ../src/shell-global.c:824
+#: ../src/shell-global.c:833
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
@@ -235,6 +228,12 @@ msgstr "Iskanje"
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"
+#~ msgid "Frequent"
+#~ msgstr "Pogosto"
+#~ msgid "More"
+#~ msgstr "Več"
+#~ msgid "(see all)"
+#~ msgstr "(poglej vse)"
#~ msgid "Browse"
#~ msgstr "Prebrskaj"
diff --git a/src/Makefile.am b/src/Makefile.am
index 3ed60b43c..4b11e83f3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -87,8 +87,6 @@ libgnome_shell_la_SOURCES = \
shell-global.c \
shell-global.h \
shell-global-private.h \
- shell-status-menu.c \
- shell-status-menu.h \
shell-stack.c \
shell-stack.h \
shell-tray-manager.c \
@@ -165,7 +163,7 @@ libgnome_shell_la_LIBADD = \
libgnome_shell_la_CPPFLAGS = $(gnome_shell_cflags)
typelibdir = $(pkglibdir)
-typelib_DATA = Shell-0.1.typelib Big-1.0.typelib St-1.0.typelib
+typelib_DATA = Shell-0.1.typelib Big-1.0.typelib St-1.0.typelib Gdm-1.0.typelib
Shell-0.1.gir: $(mutter) $(G_IR_SCANNER) Big-1.0.gir St-1.0.gir libgnome-shell.la Makefile
$(AM_V_GEN) $(G_IR_SCANNER) \
@@ -237,3 +235,22 @@ St-1.0.typelib: St-1.0.gir
$< -o $@
CLEANFILES += St-1.0.typelib
+
+Gdm-1.0.gir: $(mutter) $(G_IR_SCANNER) libgdmuser-1.0.la Makefile
+ $(AM_V_GEN) $(G_IR_SCANNER) \
+ --namespace=Gdm \
+ --nsversion=1.0 \
+ --include=GObject-2.0 \
+ --include=GdkPixbuf-2.0 \
+ --libtool="$(LIBTOOL)" \
+ --library=libgdmuser-1.0.la \
+ $(addprefix $(srcdir)/,$(gdmuser_source_h)) \
+ $(addprefix $(srcdir)/,$(gdmuser_source_c)) \
+ $(gdmuser_cflags) \
+ -o $@
+CLEANFILES += Gdm-1.0.gir
+
+Gdm-1.0.typelib: libbig-1.0.la Gdm-1.0.gir
+ $(AM_V_GEN) $(G_IR_COMPILER) Gdm-1.0.gir -o $@
+CLEANFILES += Gdm-1.0.typelib
+
diff --git a/src/gdmuser/gdm-user-manager.c b/src/gdmuser/gdm-user-manager.c
index 167ca7d55..e636b3564 100644
--- a/src/gdmuser/gdm-user-manager.c
+++ b/src/gdmuser/gdm-user-manager.c
@@ -998,7 +998,7 @@ gdm_user_manager_get_user (GdmUserManager *manager,
GdmUser *
gdm_user_manager_get_user_by_uid (GdmUserManager *manager,
- uid_t uid)
+ gulong uid)
{
GdmUser *user;
struct passwd *pwent;
diff --git a/src/gdmuser/gdm-user-manager.h b/src/gdmuser/gdm-user-manager.h
index 6c696e585..bb1118090 100644
--- a/src/gdmuser/gdm-user-manager.h
+++ b/src/gdmuser/gdm-user-manager.h
@@ -75,7 +75,7 @@ GSList * gdm_user_manager_list_users (GdmUserManager *mana
GdmUser * gdm_user_manager_get_user (GdmUserManager *manager,
const char *user_name);
GdmUser * gdm_user_manager_get_user_by_uid (GdmUserManager *manager,
- uid_t uid);
+ gulong uid);
gboolean gdm_user_manager_activate_user_session (GdmUserManager *manager,
GdmUser *user);
diff --git a/src/gdmuser/gdm-user.c b/src/gdmuser/gdm-user.c
index 4accb56ed..940c6877b 100644
--- a/src/gdmuser/gdm-user.c
+++ b/src/gdmuser/gdm-user.c
@@ -516,7 +516,7 @@ _gdm_user_icon_changed (GdmUser *user)
* Since: 1.0
**/
-uid_t
+gulong
gdm_user_get_uid (GdmUser *user)
{
g_return_val_if_fail (GDM_IS_USER (user), -1);
diff --git a/src/gdmuser/gdm-user.h b/src/gdmuser/gdm-user.h
index 4edd3baf4..ee5dc509b 100644
--- a/src/gdmuser/gdm-user.h
+++ b/src/gdmuser/gdm-user.h
@@ -39,7 +39,7 @@ typedef struct _GdmUser GdmUser;
GType gdm_user_get_type (void) G_GNUC_CONST;
-uid_t gdm_user_get_uid (GdmUser *user);
+gulong gdm_user_get_uid (GdmUser *user);
G_CONST_RETURN char *gdm_user_get_user_name (GdmUser *user);
G_CONST_RETURN char *gdm_user_get_real_name (GdmUser *user);
G_CONST_RETURN char *gdm_user_get_home_directory (GdmUser *user);
diff --git a/src/gnome-shell.in b/src/gnome-shell.in
old mode 100644
new mode 100755
index 2acc967ed..b009ec495
--- a/src/gnome-shell.in
+++ b/src/gnome-shell.in
@@ -53,9 +53,7 @@ def start_xephyr():
time.sleep(1)
# Start some windows in our session.
- subprocess.Popen(["xterm", "-geometry", "+30+30"])
- subprocess.Popen(["xlogo", "-geometry", "-0-0"])
- subprocess.Popen(["xeyes", "-geometry", "-0+30"])
+ subprocess.Popen(["gnome-terminal"])
return xephyr;
@@ -212,6 +210,8 @@ parser.add_option("", "--geometry", metavar="GEOMETRY",
default="1024x768");
parser.add_option("-w", "--wide", action="store_true",
help="Use widescreen (1280x800) with Xephyr")
+parser.add_option("", "--eval-file", metavar="EVAL_FILE",
+ help="Evaluate the contents of the given JavaScript file")
options, args = parser.parse_args()
@@ -219,6 +219,20 @@ if args:
parser.print_usage()
sys.exit(1)
+if options.eval_file:
+ import dbus
+
+ f = open(options.eval_file)
+ contents = f.read()
+ f.close()
+
+ session = dbus.SessionBus()
+ shell = session.get_object('org.gnome.Shell', '/org/gnome/Shell')
+ shell = dbus.Interface(shell, 'org.gnome.Shell')
+ result = shell.Eval(contents)
+ print result
+ sys.exit(0)
+
if options.debug_command:
options.debug = True
elif options.debug:
diff --git a/src/shell-app-system.c b/src/shell-app-system.c
index 898fd0f95..2ec877472 100644
--- a/src/shell-app-system.c
+++ b/src/shell-app-system.c
@@ -740,6 +740,8 @@ shell_app_info_get_name (ShellAppInfo *info)
{
char *title;
g_object_get (info->window, "title", &title, NULL);
+ if (!title)
+ title = g_strdup ("");
return title;
}
}
diff --git a/src/shell-global.c b/src/shell-global.c
index b07d0905f..5bb7e69d4 100644
--- a/src/shell-global.c
+++ b/src/shell-global.c
@@ -1026,3 +1026,36 @@ shell_get_event_state (ClutterEvent *event)
ClutterModifierType state = clutter_event_get_state (event);
return state & CLUTTER_MODIFIER_MASK;
}
+
+static void
+shell_popup_menu_position_func (GtkMenu *menu,
+ int *x,
+ int *y,
+ gboolean *push_in,
+ gpointer user_data)
+{
+ *x = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menu), "shell-menu-x"));
+ *y = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menu), "shell-menu-y"));
+}
+
+/**
+ * shell_popup_menu:
+ * @menu: a #GtkMenu
+ * @button: mouse button that triggered the menu
+ * @time: timestamp of event that triggered the menu
+ * @menu_x: x coordinate to display the menu at
+ * @menu_y: y coordinate to display the menu at
+ *
+ * Wraps gtk_menu_popup(), but using @menu_x, @menu_y for the location
+ * rather than needing a callback.
+ **/
+void
+shell_popup_menu (GtkMenu *menu, int button, guint32 time,
+ int menu_x, int menu_y)
+{
+ g_object_set_data (G_OBJECT (menu), "shell-menu-x", GINT_TO_POINTER (menu_x));
+ g_object_set_data (G_OBJECT (menu), "shell-menu-y", GINT_TO_POINTER (menu_y));
+
+ gtk_menu_popup (menu, NULL, NULL, shell_popup_menu_position_func, NULL,
+ button, time);
+}
diff --git a/src/shell-global.h b/src/shell-global.h
index 55844a3a4..60b9cb552 100644
--- a/src/shell-global.h
+++ b/src/shell-global.h
@@ -79,6 +79,10 @@ GdkModifierType shell_global_get_modifier_keys (ShellGlobal *global);
ClutterModifierType shell_get_event_state (ClutterEvent *event);
+void shell_popup_menu (GtkMenu *menu, int button, guint32 time,
+ int menu_x, int menu_y);
+
+
G_END_DECLS
#endif /* __SHELL_GLOBAL_H__ */
diff --git a/src/shell-status-menu.c b/src/shell-status-menu.c
deleted file mode 100644
index 4018faf3c..000000000
--- a/src/shell-status-menu.c
+++ /dev/null
@@ -1,732 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-/* Adapted from gdm/gui/user-switch-applet/applet.c */
-/*
- *
- * Copyright (C) 2004-2005 James M. Cape .
- * Copyright (C) 2008,2009 Red Hat, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include "shell-status-menu.h"
-
-#include
-#include
-#include
-
-#include
-#include
-#include
-
-#include
-#include
-
-#include
-
-#define GDMUSER_I_KNOW_THIS_IS_UNSTABLE
-#include
-
-#include "shell-global.h"
-#include "shell-gconf.h"
-
-#define LOCKDOWN_DIR "/desktop/gnome/lockdown"
-#define LOCKDOWN_KEY LOCKDOWN_DIR "/disable_user_switching"
-
-#define SIDEBAR_VISIBLE_KEY SHELL_GCONF_DIR "/sidebar/visible"
-
-struct _ShellStatusMenuPrivate {
- GConfClient *client;
- GdmUserManager *manager;
- GdmUser *user;
-
- ClutterTexture *user_icon;
- BigBox *name_box;
- ClutterText *name;
-
- GtkWidget *menu;
- GtkWidget *account_item;
- GtkWidget *sidebar_item;
- GtkWidget *control_panel_item;
- GtkWidget *lock_screen_item;
- GtkWidget *login_screen_item;
- GtkWidget *quit_session_item;
- GtkWidget *shut_down_item;
-
- guint client_notify_lockdown_id;
-
- guint current_status_state;
-
- guint user_icon_changed_id;
- guint user_notify_id;
-
- gboolean has_other_users;
-
- GtkIconSize icon_size;
- guint pixel_size;
-};
-
-enum {
- PROP_0
-};
-
-G_DEFINE_TYPE(ShellStatusMenu, shell_status_menu, BIG_TYPE_BOX);
-
-/* Signals */
-enum
-{
- DEACTIVATED,
- LAST_SIGNAL
-};
-
-static guint shell_status_menu_signals [LAST_SIGNAL] = { 0 };
-
-static void
-reset_icon (ShellStatusMenu *status)
-{
- ShellStatusMenuPrivate *priv = status->priv;
- GdkPixbuf *pixbuf;
-
- if (priv->user == NULL)
- return;
-
- if (priv->user_icon != NULL)
- {
- pixbuf = gdm_user_render_icon (priv->user, 24);
-
- if (pixbuf == NULL)
- return;
-
- shell_clutter_texture_set_from_pixbuf (priv->user_icon, pixbuf);
-
- g_object_unref (pixbuf);
- }
-}
-
-static void
-update_name_text (ShellStatusMenu *status)
-{
- ShellStatusMenuPrivate *priv = status->priv;
-
- clutter_text_set_text (priv->name,
- gdm_user_get_real_name (GDM_USER (priv->user)));
-}
-
-static void
-on_user_icon_changed (GdmUser *user,
- ShellStatusMenu *status)
-{
- g_debug ("User icon changed");
- reset_icon (status);
-}
-
-static void
-user_notify_display_name_cb (GObject *object,
- GParamSpec *pspec,
- ShellStatusMenu *status)
-{
- update_name_text (status);
-}
-
-static void
-setup_current_user (ShellStatusMenu *status)
-{
- ShellStatusMenuPrivate *priv = status->priv;
- const char *name;
-
- priv->user = gdm_user_manager_get_user_by_uid (priv->manager, getuid ());
- if (priv->user != NULL)
- {
- g_object_ref (priv->user);
- name = gdm_user_get_real_name (priv->user);
- }
- else
- {
- name = _("Unknown");
- }
-
- update_name_text (status);
-
- if (priv->user != NULL)
- {
- reset_icon (status);
-
- priv->user_icon_changed_id =
- g_signal_connect (priv->user,
- "icon-changed",
- G_CALLBACK (on_user_icon_changed),
- status);
- priv->user_notify_id =
- g_signal_connect (priv->user,
- "notify::display-name",
- G_CALLBACK (user_notify_display_name_cb),
- status);
- }
-}
-
-static void
-maybe_lock_screen (ShellStatusMenu *status)
-{
- char *args[3];
- GError *err;
- GdkScreen *screen;
- gboolean use_gscreensaver = TRUE;
- gboolean res;
-
- g_debug ("Attempting to lock screen");
-
- args[0] = g_find_program_in_path ("gnome-screensaver-command");
- if (args[0] == NULL)
- {
- args[0] = g_find_program_in_path ("xscreensaver-command");
- use_gscreensaver = FALSE;
- }
-
- if (args[0] == NULL)
- return;
-
- if (use_gscreensaver)
- args[1] = "--lock";
- else
- args[1] = "-lock";
- args[2] = NULL;
-
- screen = gdk_screen_get_default ();
-
- err = NULL;
- res = gdk_spawn_on_screen (screen, g_get_home_dir (), args, NULL, 0, NULL,
- NULL, NULL, &err);
- if (!res)
- {
- g_warning (_("Can't lock screen: %s"), err->message);
- g_error_free (err);
- }
-
- if (use_gscreensaver)
- args[1] = "--throttle";
- else
- args[1] = "-throttle";
-
- err = NULL;
- res = gdk_spawn_on_screen (screen, g_get_home_dir (), args, NULL,
- (G_SPAWN_STDERR_TO_DEV_NULL | G_SPAWN_STDOUT_TO_DEV_NULL), NULL, NULL,
- NULL, &err);
- if (!res)
- {
- g_warning (_("Can't temporarily set screensaver to blank screen: %s"),
- err->message);
- g_error_free (err);
- }
-
- g_free (args[0]);
-}
-
-static void
-on_lock_screen_activate (GtkMenuItem *item,
- ShellStatusMenu *status)
-{
- maybe_lock_screen (status);
-}
-
-static void
-do_switch (ShellStatusMenu *status,
- GdmUser *user)
-{
- ShellStatusMenuPrivate *priv = status->priv;
- guint num_sessions;
-
- g_debug ("Do user switch");
-
- if (user == NULL)
- {
- gdm_user_manager_goto_login_session (priv->manager);
- goto out;
- }
-
- num_sessions = gdm_user_get_num_sessions (user);
- if (num_sessions > 0)
- gdm_user_manager_activate_user_session (priv->manager, user);
- else
- gdm_user_manager_goto_login_session (priv->manager);
-out:
- maybe_lock_screen (status);
-}
-
-static void
-on_login_screen_activate (GtkMenuItem *item,
- ShellStatusMenu *status)
-{
- GdmUser *user;
-
- user = NULL;
-
- do_switch (status, user);
-}
-
-static void
-spawn_external (ShellStatusMenu *status, const char *program)
-{
- char *args[2];
- GError *error;
- GdkScreen *screen;
- gboolean res;
-
- args[0] = g_find_program_in_path (program);
- if (args[0] == NULL)
- return;
- args[1] = NULL;
-
- screen = gdk_screen_get_default ();
-
- error = NULL;
- res = gdk_spawn_on_screen (screen, g_get_home_dir (), args, NULL, 0, NULL,
- NULL, NULL, &error);
- if (!res)
- {
- g_warning ("Failed to exec %s: %s", program, error->message);
- g_clear_error (&error);
- }
-
- g_free (args[0]);
-
-}
-
-static void
-on_control_panel_activate (GtkMenuItem *item,
- ShellStatusMenu *status)
-{
- spawn_external (status, "gnome-control-center");
-}
-
-static void
-on_account_activate (GtkMenuItem *item,
- ShellStatusMenu *status)
-{
- spawn_external (status, "gnome-about-me");
-}
-
-static void
-on_sidebar_toggled (GtkCheckMenuItem *item,
- ShellStatusMenu *status)
-{
- gconf_client_set_bool (status->priv->client, SIDEBAR_VISIBLE_KEY,
- gtk_check_menu_item_get_active (item), NULL);
-}
-
-
-/* Calls 'gnome-session-save arg' */
-static void
-gnome_session_save_command (const char *arg)
-{
- char *args[3];
- GError *error;
- GdkScreen *screen;
- gboolean res;
-
- args[0] = g_find_program_in_path ("gnome-session-save");
- if (args[0] == NULL)
- return;
-
- args[1] = (char *)arg;
- args[2] = NULL;
-
- screen = gdk_screen_get_default ();
-
- error = NULL;
- res = gdk_spawn_on_screen (screen, g_get_home_dir (), args, NULL, 0, NULL,
- NULL, NULL, &error);
- if (!res)
- {
- g_warning (_("Can't logout: %s"), error->message);
- g_error_free (error);
- }
-
- g_free (args[0]);
-}
-
-
-static void
-on_quit_session_activate (GtkMenuItem *item,
- ShellStatusMenu *status)
-{
- gnome_session_save_command ("--logout-dialog");
-}
-
-static void
-on_shut_down_activate (GtkMenuItem *item,
- ShellStatusMenu *status)
-{
- gnome_session_save_command ("--shutdown-dialog");
-}
-
-static void
-update_switch_user (ShellStatusMenu *status)
-{
- ShellStatusMenuPrivate *priv = status->priv;
- GSList *users;
-
- users = gdm_user_manager_list_users (priv->manager);
- priv->has_other_users = FALSE;
- if (users != NULL)
- priv->has_other_users = g_slist_length (users) > 1;
- g_slist_free (users);
-
- if (priv->has_other_users)
- gtk_widget_show (priv->login_screen_item);
- else
- gtk_widget_hide (priv->login_screen_item);
-}
-
-static void
-on_manager_user_added (GdmUserManager *manager,
- GdmUser *user,
- ShellStatusMenu *status)
-{
- update_switch_user (status);
-}
-
-static void
-on_manager_user_removed (GdmUserManager *manager,
- GdmUser *user,
- ShellStatusMenu *status)
-{
- update_switch_user (status);
-}
-
-static void
-on_manager_users_loaded (GdmUserManager *manager,
- ShellStatusMenu *status)
-{
- update_switch_user (status);
-}
-
-static void
-menu_style_set_cb (GtkWidget *menu, GtkStyle *old_style,
- ShellStatusMenu *status)
-{
- ShellStatusMenuPrivate *priv = status->priv;
- GtkSettings *settings;
- int width;
- int height;
-
- priv->icon_size = gtk_icon_size_from_name ("panel-menu");
- if (priv->icon_size == GTK_ICON_SIZE_INVALID)
- priv->icon_size = gtk_icon_size_register ("panel-menu", 24, 24);
-
- if (gtk_widget_has_screen (menu))
- settings = gtk_settings_get_for_screen (gtk_widget_get_screen (menu));
- else
- settings = gtk_settings_get_default ();
-
- if (!gtk_icon_size_lookup_for_settings (settings, priv->icon_size, &width,
- &height))
- priv->pixel_size = -1;
- else
- priv->pixel_size = MAX(width, height);
-}
-
-static void
-menuitem_style_set_cb (GtkWidget *menuitem,
- GtkStyle *old_style,
- ShellStatusMenu *status)
-{
- GtkWidget *image;
- const char *icon_name;
- ShellStatusMenuPrivate *priv = status->priv;
-
- if (menuitem == priv->login_screen_item)
- icon_name = "system-users";
- else if (menuitem == priv->lock_screen_item)
- icon_name = "system-lock-screen";
- else if (menuitem == priv->quit_session_item)
- icon_name = "system-log-out";
- else if (menuitem == priv->account_item)
- icon_name = "user-info";
- else if (menuitem == priv->control_panel_item)
- icon_name = "preferences-desktop";
- else if (menuitem == priv->shut_down_item)
- icon_name = "system-shutdown";
- else
- icon_name = GTK_STOCK_MISSING_IMAGE;
-
- image = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (menuitem));
- gtk_image_set_pixel_size (GTK_IMAGE (image), priv->pixel_size);
- gtk_image_set_from_icon_name (GTK_IMAGE (image), icon_name, priv->icon_size);
-}
-
-static void
-on_deactivate (GtkMenuShell *menushell, gpointer user_data)
-{
- ShellStatusMenu *status = SHELL_STATUS_MENU (user_data);
- g_signal_emit (G_OBJECT (status), shell_status_menu_signals[DEACTIVATED], 0);
-}
-
-static void
-create_sub_menu (ShellStatusMenu *status)
-{
- ShellStatusMenuPrivate *priv = status->priv;
- GtkWidget *item;
-
- priv->menu = gtk_menu_new ();
- g_signal_connect (priv->menu, "style-set", G_CALLBACK (menu_style_set_cb),
- status);
-
- g_signal_connect (priv->manager, "users-loaded",
- G_CALLBACK (on_manager_users_loaded), status);
- g_signal_connect (priv->manager, "user-added",
- G_CALLBACK (on_manager_user_added), status);
- g_signal_connect (priv->manager, "user-removed",
- G_CALLBACK (on_manager_user_removed), status);
-
- priv->account_item = gtk_image_menu_item_new_with_label (_("Account Information..."));
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (priv->account_item),
- gtk_image_new ());
- gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), priv->account_item);
- g_signal_connect (priv->account_item, "style-set",
- G_CALLBACK (menuitem_style_set_cb), status);
- g_signal_connect (priv->account_item, "activate",
- G_CALLBACK (on_account_activate), status);
- gtk_widget_show (priv->account_item);
-
- priv->sidebar_item = gtk_check_menu_item_new_with_label (_("Sidebar"));
- gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (priv->sidebar_item),
- gconf_client_get_bool (priv->client, SIDEBAR_VISIBLE_KEY, NULL));
- gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), priv->sidebar_item);
- g_signal_connect (priv->sidebar_item, "toggled",
- G_CALLBACK (on_sidebar_toggled), status);
- gtk_widget_show (priv->sidebar_item);
-
- priv->control_panel_item = gtk_image_menu_item_new_with_label (_("System Preferences..."));
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (priv->control_panel_item),
- gtk_image_new ());
- gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), priv->control_panel_item);
- g_signal_connect (priv->control_panel_item, "style-set",
- G_CALLBACK (menuitem_style_set_cb), status);
- g_signal_connect (priv->control_panel_item, "activate",
- G_CALLBACK (on_control_panel_activate), status);
- gtk_widget_show (priv->control_panel_item);
-
- item = gtk_separator_menu_item_new ();
- gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), item);
- gtk_widget_show (item);
-
- priv->lock_screen_item
- = gtk_image_menu_item_new_with_label (_("Lock Screen"));
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (priv->lock_screen_item),
- gtk_image_new ());
- gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), priv->lock_screen_item);
- g_signal_connect (priv->lock_screen_item, "style-set",
- G_CALLBACK (menuitem_style_set_cb), status);
- g_signal_connect (priv->lock_screen_item, "activate",
- G_CALLBACK (on_lock_screen_activate), status);
- gtk_widget_show (priv->lock_screen_item);
-
- priv->login_screen_item = gtk_image_menu_item_new_with_label (_("Switch User"));
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (priv->login_screen_item),
- gtk_image_new ());
- gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), priv->login_screen_item);
- g_signal_connect (priv->login_screen_item, "style-set",
- G_CALLBACK (menuitem_style_set_cb), status);
- g_signal_connect (priv->login_screen_item, "activate",
- G_CALLBACK (on_login_screen_activate), status);
- /* Only show switch user if there are other users */
-
- /* Log Out */
- priv->quit_session_item = gtk_image_menu_item_new_with_label (_("Log Out..."));
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (priv->quit_session_item),
- gtk_image_new ());
- gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), priv->quit_session_item);
- g_signal_connect (priv->quit_session_item, "style-set",
- G_CALLBACK (menuitem_style_set_cb), status);
- g_signal_connect (priv->quit_session_item, "activate",
- G_CALLBACK (on_quit_session_activate), status);
- gtk_widget_show (priv->quit_session_item);
-
- /* Shut down */
- priv->shut_down_item = gtk_image_menu_item_new_with_label (_("Shut Down..."));
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (priv->shut_down_item),
- gtk_image_new ());
- gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), priv->shut_down_item);
- g_signal_connect (priv->shut_down_item, "style-set",
- G_CALLBACK (menuitem_style_set_cb), status);
- g_signal_connect (priv->shut_down_item, "activate",
- G_CALLBACK (on_shut_down_activate), status);
- gtk_widget_show (priv->shut_down_item);
-
- g_signal_connect (G_OBJECT (priv->menu), "deactivate",
- G_CALLBACK (on_deactivate), status);
-}
-
-static void
-shell_status_menu_init (ShellStatusMenu *status)
-{
- ShellStatusMenuPrivate *priv;
-
- status->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (status, SHELL_TYPE_STATUS_MENU,
- ShellStatusMenuPrivate);
-
- g_object_set (G_OBJECT (status),
- "orientation", BIG_BOX_ORIENTATION_HORIZONTAL,
- NULL);
- priv->client = gconf_client_get_default ();
-
- priv->user_icon = CLUTTER_TEXTURE (clutter_texture_new ());
- big_box_append (BIG_BOX (status), CLUTTER_ACTOR (status->priv->user_icon), 0);
-
- priv->name_box = BIG_BOX (big_box_new (BIG_BOX_ORIENTATION_VERTICAL));
- g_object_set (G_OBJECT (priv->name_box), "y-align", BIG_BOX_ALIGNMENT_CENTER, NULL);
- big_box_append (BIG_BOX (status), CLUTTER_ACTOR (priv->name_box), BIG_BOX_PACK_EXPAND);
- priv->name = CLUTTER_TEXT (clutter_text_new ());
- big_box_append (BIG_BOX (priv->name_box), CLUTTER_ACTOR (priv->name), BIG_BOX_PACK_EXPAND);
-
- priv->manager = gdm_user_manager_ref_default ();
- setup_current_user (status);
-
- create_sub_menu (status);
-}
-
-static void
-shell_status_menu_finalize (GObject *object)
-{
- ShellStatusMenu *status = SHELL_STATUS_MENU (object);
- ShellStatusMenuPrivate *priv = status->priv;
-
- gconf_client_notify_remove (priv->client, priv->client_notify_lockdown_id);
-
- g_signal_handler_disconnect (priv->user, priv->user_notify_id);
- g_signal_handler_disconnect (priv->user, priv->user_icon_changed_id);
-
- if (priv->user != NULL) {
- g_object_unref (priv->user);
- }
- g_object_unref (priv->client);
- g_object_unref (priv->manager);
-
- G_OBJECT_CLASS (shell_status_menu_parent_class)->finalize (object);
-}
-
-static void
-shell_status_menu_class_init (ShellStatusMenuClass *klass)
-{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-
- g_type_class_add_private (klass, sizeof (ShellStatusMenuPrivate));
-
- gobject_class->finalize = shell_status_menu_finalize;
-
- shell_status_menu_signals[DEACTIVATED] =
- g_signal_new ("deactivated",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ShellStatusMenuClass, deactivated),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-}
-
-static void
-position_menu (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data)
-{
- ShellStatusMenu *status = SHELL_STATUS_MENU (user_data);
- ClutterActor *parent;
- float src_x, src_y;
- float width, height;
- int menu_width;
-
- gtk_widget_get_size_request (GTK_WIDGET (menu), &menu_width, NULL);
-
- /* Encapsulation breakage: it looks better if the menu is
- * aligned with the bottom of the actor's grandparent - the
- * panel, rather than with the bottom of the actor. We just
- * assume what the hierarchy is and where we are positioned
- * in the panel.
- */
- parent = clutter_actor_get_parent (CLUTTER_ACTOR (status));
- parent = clutter_actor_get_parent (parent);
- clutter_actor_get_transformed_position (parent, &src_x, &src_y);
- clutter_actor_get_transformed_size (parent, &width, &height);
- *x = (gint)(0.5 + src_x + width - menu_width);
- *y = (gint)(0.5 + src_y + height);
-}
-
-/**
- * shell_status_menu_toggle:
- * @menu: a #ShellStatusMenu
- *
- * If the menu is not currently up, pops it up. Otherwise, hides it.
- * Popping up may fail if another grab is already active; check with
- * shell_status_menu_is_active().
- */
-void
-shell_status_menu_toggle (ShellStatusMenu *status, ClutterEvent *event)
-{
- ShellStatusMenuPrivate *priv = status->priv;
-
- if (GTK_WIDGET_VISIBLE (priv->menu))
- {
- gtk_menu_popdown (GTK_MENU (priv->menu));
- }
- else
- {
- /* We don't want to overgrab a Mutter grab with the grab that GTK+
- * uses on menus.
- */
- ShellGlobal *global = shell_global_get ();
- if (shell_global_display_is_grabbed (global))
- return;
-
- gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL, position_menu,
- status, 1, event->button.time);
- }
-}
-
-/**
- * shell_status_menu_is_active:
- * @menu: a #ShellStatusMenu
- *
- * Gets whether the menu is currently popped up
- *
- * Return value: %TRUE if the menu is currently popped up
- */
-gboolean
-shell_status_menu_is_active (ShellStatusMenu *status)
-{
- ShellStatusMenuPrivate *priv = status->priv;
-
- return GTK_WIDGET_VISIBLE (priv->menu);
-}
-
-/**
- * shell_status_menu_get_name:
- * @menu: a #ShellStatusMenu
- *
- * Return value: (transfer none): the #ClutterText actor with the user's name.
- */
-ClutterText *
-shell_status_menu_get_name (ShellStatusMenu *menu)
-{
- return menu->priv->name;
-}
-
-/**
- * shell_status_menu_get_icon:
- * @menu: a #ShellStatusMenu
- *
- * Return value: (transfer none): the #ClutterTexture actor with the user icon.
- */
-ClutterTexture *
-shell_status_menu_get_icon (ShellStatusMenu *menu)
-{
- return menu->priv->user_icon;
-}
diff --git a/src/shell-status-menu.h b/src/shell-status-menu.h
deleted file mode 100644
index 9a7c2969f..000000000
--- a/src/shell-status-menu.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-
-#ifndef __SHELL_STATUS_MENU_H__
-#define __SHELL_STATUS_MENU_H__
-
-#include
-#include "big/box.h"
-
-G_BEGIN_DECLS
-
-#define SHELL_TYPE_STATUS_MENU (shell_status_menu_get_type ())
-#define SHELL_STATUS_MENU(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_STATUS_MENU, ShellStatusMenu))
-#define SHELL_STATUS_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_STATUS_MENU, ShellStatusMenuClass))
-#define SHELL_IS_STATUS_MENU(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SHELL_TYPE_STATUS_MENU))
-#define SHELL_IS_STATUS_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_STATUS_MENU))
-#define SHELL_STATUS_MENU_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_STATUS_MENU, ShellStatusMenuClass))
-
-typedef struct _ShellStatusMenu ShellStatusMenu;
-typedef struct _ShellStatusMenuPrivate ShellStatusMenuPrivate;
-typedef struct _ShellStatusMenuClass ShellStatusMenuClass;
-
-struct _ShellStatusMenu
-{
- BigBox parent_instance;
-
- ShellStatusMenuPrivate *priv;
-};
-
-struct _ShellStatusMenuClass
-{
- BigBoxClass parent_class;
-
- void (*deactivated) (ShellStatusMenu *status, gpointer user_data);
-};
-
-GType shell_status_menu_get_type (void);
-
-void shell_status_menu_toggle (ShellStatusMenu *menu, ClutterEvent *event);
-gboolean shell_status_menu_is_active (ShellStatusMenu *menu);
-ClutterText *shell_status_menu_get_name (ShellStatusMenu *menu);
-ClutterTexture *shell_status_menu_get_icon (ShellStatusMenu *menu);
-
-G_END_DECLS
-
-#endif /* __SHELL_STATUS_MENU_H__ */
diff --git a/src/st/st-bin.c b/src/st/st-bin.c
index 4c862b62a..48347b6ba 100644
--- a/src/st/st-bin.c
+++ b/src/st/st-bin.c
@@ -545,7 +545,7 @@ st_bin_new (void)
/**
* st_bin_set_child:
* @bin: a #StBin
- * @child: a #ClutterActor, or %NULL
+ * @child: (allow-none): a #ClutterActor, or %NULL
*
* Sets @child as the child of @bin.
*
diff --git a/src/st/st-box-layout.c b/src/st/st-box-layout.c
index 180d893c4..88c2d9309 100644
--- a/src/st/st-box-layout.c
+++ b/src/st/st-box-layout.c
@@ -21,6 +21,20 @@
*
*/
+/* Portions copied from Clutter:
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Authored By Matthew Allum
+ *
+ * Copyright (C) 2006 OpenedHand
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ */
+
/**
* SECTION:st-box-layout
* @short_description: a layout container arranging children in a single line
@@ -246,6 +260,8 @@ st_box_container_add_actor (ClutterContainer *container,
priv->children = g_list_append (priv->children, actor);
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (container));
+
g_signal_emit_by_name (container, "actor-added", actor);
}
@@ -294,8 +310,42 @@ st_box_container_lower (ClutterContainer *container,
ClutterActor *actor,
ClutterActor *sibling)
{
- /* XXX: not yet implemented */
- g_warning ("%s() not yet implemented", __FUNCTION__);
+ StBoxLayoutPrivate *priv = ST_BOX_LAYOUT (container)->priv;
+
+ /* copied from clutter/clutter/clutter-group.c */
+
+ priv->children = g_list_remove (priv->children, actor);
+
+ /* Push to bottom */
+ if (!sibling)
+ {
+ GList *last_item;
+
+ last_item = g_list_first (priv->children);
+
+ if (last_item)
+ sibling = last_item->data;
+
+ priv->children = g_list_prepend (priv->children, actor);
+ }
+ else
+ {
+ gint pos;
+
+ pos = g_list_index (priv->children, sibling);
+
+ priv->children = g_list_insert (priv->children, actor, pos);
+ }
+
+ /* See comment in group_raise for this */
+ if (sibling &&
+ clutter_actor_get_depth (sibling) != clutter_actor_get_depth (actor))
+ {
+ clutter_actor_set_depth (actor, clutter_actor_get_depth (sibling));
+ }
+
+ if (CLUTTER_ACTOR_IS_VISIBLE (container))
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (container));
}
static void
@@ -303,8 +353,47 @@ st_box_container_raise (ClutterContainer *container,
ClutterActor *actor,
ClutterActor *sibling)
{
- /* XXX: not yet implemented */
- g_warning ("%s() not yet implemented", __FUNCTION__);
+ StBoxLayoutPrivate *priv = ST_BOX_LAYOUT (container)->priv;
+
+ priv->children = g_list_remove (priv->children, actor);
+
+ /* copied from clutter/clutter/clutter-group.c */
+
+ /* Raise at the top */
+ if (!sibling)
+ {
+ GList *last_item;
+
+ last_item = g_list_last (priv->children);
+
+ if (last_item)
+ sibling = last_item->data;
+
+ priv->children = g_list_append (priv->children, actor);
+ }
+ else
+ {
+ gint pos;
+
+ pos = g_list_index (priv->children, sibling) + 1;
+
+ priv->children = g_list_insert (priv->children, actor, pos);
+ }
+
+ /* set Z ordering a value below, this will then call sort
+ * as values are equal ordering shouldn't change but Z
+ * values will be correct.
+ *
+ * FIXME: optimise
+ */
+ if (sibling &&
+ clutter_actor_get_depth (sibling) != clutter_actor_get_depth (actor))
+ {
+ clutter_actor_set_depth (actor, clutter_actor_get_depth (sibling));
+ }
+
+ if (CLUTTER_ACTOR_IS_VISIBLE (container))
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (container));
}
static void
@@ -714,6 +803,8 @@ st_box_layout_allocate (ClutterActor *actor,
gint n_expand_children = 0, i;
gfloat expand_amount, shrink_amount;
BoxChildShrink *shrinks = NULL;
+ gboolean flip = (st_widget_get_direction (ST_WIDGET (actor)) == ST_TEXT_DIRECTION_RTL)
+ && (!priv->is_vertical);
CLUTTER_ACTOR_CLASS (st_box_layout_parent_class)->allocate (actor, box,
flags);
@@ -808,6 +899,8 @@ st_box_layout_allocate (ClutterActor *actor,
if (priv->is_vertical)
position = content_box.y1;
+ else if (flip)
+ position = content_box.x2;
else
position = content_box.x1;
@@ -865,7 +958,10 @@ st_box_layout_allocate (ClutterActor *actor,
else if (shrink_amount > 0)
child_allocated -= shrinks[i].shrink_amount;
- next_position = position + child_allocated;
+ if (flip)
+ next_position = position - child_allocated;
+ else
+ next_position = position + child_allocated;
if (priv->is_vertical)
{
@@ -883,8 +979,17 @@ st_box_layout_allocate (ClutterActor *actor,
}
else
{
- child_box.x1 = (int)(0.5 + position);
- child_box.x2 = (int)(0.5 + next_position);
+ if (flip)
+ {
+ child_box.x1 = (int)(0.5 + next_position);
+ child_box.x2 = (int)(0.5 + position);
+ }
+ else
+ {
+ child_box.x1 = (int)(0.5 + position);
+ child_box.x2 = (int)(0.5 + next_position);
+ }
+
child_box.y1 = content_box.y1;
if (priv->vadjustment)
child_box.y2 = content_box.y1 + MAX (avail_height, natural_height);
@@ -895,7 +1000,10 @@ st_box_layout_allocate (ClutterActor *actor,
clutter_actor_allocate (child, &child_box, flags);
}
- position = next_position + priv->spacing;
+ if (flip)
+ position = next_position - priv->spacing;
+ else
+ position = next_position + priv->spacing;
next_child:
if (priv->is_pack_start)
@@ -1251,3 +1359,62 @@ st_box_layout_get_pack_start (StBoxLayout *box)
return box->priv->is_pack_start;
}
+
+static void
+st_box_layout_internal_remove_all (StBoxLayout *self,
+ gboolean destroy)
+{
+ StBoxLayoutPrivate *priv = ST_BOX_LAYOUT (self)->priv;
+ ClutterActor *child;
+
+ while (priv->children)
+ {
+ child = priv->children->data;
+
+ g_object_ref (child);
+ priv->children = g_list_delete_link (priv->children, priv->children);
+ clutter_actor_unparent (child);
+ g_signal_emit_by_name (self, "actor-removed", child);
+ if (destroy)
+ clutter_actor_destroy (child);
+ g_object_unref (child);
+ }
+
+ clutter_actor_queue_relayout ((ClutterActor*) self);
+}
+
+/**
+ * st_box_layout_remove_all:
+ * @self:
+ *
+ * Efficiently unparent all children currently in this box.
+ */
+void
+st_box_layout_remove_all (StBoxLayout *self)
+{
+ st_box_layout_internal_remove_all (self, FALSE);
+}
+
+/**
+ * st_box_layout_destroy_children:
+ * @self:
+ *
+ * Efficiently unparent and destroy all children currently in this box.
+ */
+void
+st_box_layout_destroy_children (StBoxLayout *self)
+{
+ st_box_layout_internal_remove_all (self, TRUE);
+}
+
+/**
+ * st_box_layout_get_n_children:
+ * @self: a #StBoxLayout
+ *
+ * Returns the number of children in this box.
+ */
+guint
+st_box_layout_get_n_children (StBoxLayout *self)
+{
+ return g_list_length (self->priv->children);
+}
diff --git a/src/st/st-box-layout.h b/src/st/st-box-layout.h
index 30954a2ee..21cd0b757 100644
--- a/src/st/st-box-layout.h
+++ b/src/st/st-box-layout.h
@@ -89,6 +89,12 @@ void st_box_layout_set_pack_start (StBoxLayout *box,
gboolean pack_start);
gboolean st_box_layout_get_pack_start (StBoxLayout *box);
+void st_box_layout_remove_all (StBoxLayout *box);
+
+void st_box_layout_destroy_children (StBoxLayout *box);
+
+guint st_box_layout_get_n_children (StBoxLayout *box);
+
G_END_DECLS
#endif /* _ST_BOX_LAYOUT_H */
diff --git a/src/st/st-table.c b/src/st/st-table.c
index e844ff6fb..42723a36c 100644
--- a/src/st/st-table.c
+++ b/src/st/st-table.c
@@ -290,7 +290,8 @@ st_table_allocate_fill (ClutterActor *child,
gdouble x_align,
gdouble y_align,
gboolean x_fill,
- gboolean y_fill)
+ gboolean y_fill,
+ gboolean ltr)
{
gfloat natural_width, natural_height;
gfloat min_width, min_height;
@@ -310,8 +311,16 @@ st_table_allocate_fill (ClutterActor *child,
if (x_fill)
{
- allocation.x1 = childbox->x1;
- allocation.x2 = (int)(allocation.x1 + available_width);
+ if (ltr)
+ {
+ allocation.x1 = childbox->x1;
+ allocation.x2 = (int)(allocation.x1 + available_width);
+ }
+ else
+ {
+ allocation.x2 = childbox->x2;
+ allocation.x1 = (int)(allocation.x2 - available_width);
+ }
}
if (y_fill)
@@ -361,8 +370,16 @@ st_table_allocate_fill (ClutterActor *child,
if (!x_fill)
{
- allocation.x1 = childbox->x1 + (int)((available_width - child_width) * x_align);
- allocation.x2 = allocation.x1 + (int) child_width;
+ if (ltr)
+ {
+ allocation.x1 = childbox->x1 + (int)((available_width - child_width) * x_align);
+ allocation.x2 = allocation.x1 + (int) child_width;
+ }
+ else
+ {
+ allocation.x2 = childbox->x2 - (int)((available_width - child_width) * x_align);
+ allocation.x1 = allocation.x2 - (int) child_width;
+ }
}
if (!y_fill)
@@ -384,6 +401,7 @@ st_table_homogeneous_allocate (ClutterActor *self,
gfloat col_width, row_height;
gint row_spacing, col_spacing;
StTablePrivate *priv = ST_TABLE (self)->priv;
+ gboolean ltr = st_widget_get_direction (ST_WIDGET (self)) == ST_TEXT_DIRECTION_LTR;
col_spacing = priv->col_spacing;
row_spacing = priv->row_spacing;
@@ -421,13 +439,21 @@ st_table_homogeneous_allocate (ClutterActor *self,
x_fill = meta->x_fill;
y_fill = meta->y_fill;
- childbox.x1 = content_box->x1 + (col_width + col_spacing) * col;
- childbox.x2 = childbox.x1 + (col_width * col_span) + (col_spacing * (col_span - 1));
+ if (ltr)
+ {
+ childbox.x1 = content_box->x1 + (col_width + col_spacing) * col;
+ childbox.x2 = childbox.x1 + (col_width * col_span) + (col_spacing * (col_span - 1));
+ }
+ else
+ {
+ childbox.x2 = content_box->x2 - (col_width + col_spacing) * col;
+ childbox.x1 = childbox.x2 - (col_width * col_span) - (col_spacing * (col_span - 1));
+ }
childbox.y1 = content_box->y1 + (row_height + row_spacing) * row;
childbox.y2 = childbox.y1 + (row_height * row_span) + (row_spacing * (row_span - 1));
- st_table_allocate_fill (child, &childbox, x_align, y_align, x_fill, y_fill);
+ st_table_allocate_fill (child, &childbox, x_align, y_align, x_fill, y_fill, ltr);
clutter_actor_allocate (child, &childbox, flags);
}
@@ -725,6 +751,7 @@ st_table_preferred_allocate (ClutterActor *self,
gint *col_widths, *row_heights;
StTable *table;
StTablePrivate *priv;
+ gboolean ltr;
table = ST_TABLE (self);
priv = ST_TABLE (self)->priv;
@@ -741,6 +768,8 @@ st_table_preferred_allocate (ClutterActor *self,
(int) (content_box->y2 - content_box->y1),
col_widths);
+ ltr = (st_widget_get_direction (ST_WIDGET (self)) == ST_TEXT_DIRECTION_LTR);
+
for (list = priv->children; list; list = g_slist_next (list))
{
@@ -808,10 +837,20 @@ st_table_preferred_allocate (ClutterActor *self,
}
/* calculate child x */
- child_x = (int) content_box->x1
- + col_spacing * col;
- for (i = 0; i < col; i++)
- child_x += col_widths[i];
+ if (ltr)
+ {
+ child_x = (int) content_box->x1
+ + col_spacing * col;
+ for (i = 0; i < col; i++)
+ child_x += col_widths[i];
+ }
+ else
+ {
+ child_x = (int) content_box->x2
+ - col_spacing * col;
+ for (i = 0; i < col; i++)
+ child_x -= col_widths[i];
+ }
/* calculate child y */
child_y = (int) content_box->y1
@@ -820,14 +859,22 @@ st_table_preferred_allocate (ClutterActor *self,
child_y += row_heights[i];
/* set up childbox */
- childbox.x1 = (float) child_x;
- childbox.x2 = (float) MAX (0, child_x + col_width);
+ if (ltr)
+ {
+ childbox.x1 = (float) child_x;
+ childbox.x2 = (float) MAX (0, child_x + col_width);
+ }
+ else
+ {
+ childbox.x2 = (float) child_x;
+ childbox.x1 = (float) MAX (0, child_x - col_width);
+ }
childbox.y1 = (float) child_y;
childbox.y2 = (float) MAX (0, child_y + row_height);
- st_table_allocate_fill (child, &childbox, x_align, y_align, x_fill, y_fill);
+ st_table_allocate_fill (child, &childbox, x_align, y_align, x_fill, y_fill, ltr);
clutter_actor_allocate (child, &childbox, flags);
}
diff --git a/src/st/st-theme-node.c b/src/st/st-theme-node.c
index e81e35ac5..cebd1afde 100644
--- a/src/st/st-theme-node.c
+++ b/src/st/st-theme-node.c
@@ -457,7 +457,7 @@ get_color_from_term (StThemeNode *node,
* parent's parent, and so forth. Note that if the property has a
* value of 'inherit' it will be inherited even if %FALSE is passed
* in for @inherit; this only affects the default behavior for inheritance.
- * @color: (out): location to store the color that was determined.
+ * @color: location to store the color that was determined.
* If the property is not found, the value in this location
* will not be changed.
*
@@ -513,7 +513,7 @@ st_theme_node_get_color (StThemeNode *node,
* parent's parent, and so forth. Note that if the property has a
* value of 'inherit' it will be inherited even if %FALSE is passed
* in for @inherit; this only affects the default behavior for inheritance.
- * @value: (out): location to store the value that was determined.
+ * @value: location to store the value that was determined.
* If the property is not found, the value in this location
* will not be changed.
*
@@ -740,7 +740,7 @@ get_length_internal (StThemeNode *node,
* parent's parent, and so forth. Note that if the property has a
* value of 'inherit' it will be inherited even if %FALSE is passed
* in for @inherit; this only affects the default behavior for inheritance.
- * @length: (out): location to store the length that was determined.
+ * @length: location to store the length that was determined.
* If the property is not found, the value in this location
* will not be changed. The returned length is resolved
* to pixels.
@@ -2199,7 +2199,7 @@ st_theme_node_adjust_preferred_height (StThemeNode *node,
* st_theme_node_get_content_box:
* @node: a #StThemeNode
* @allocation: the box allocated to a #ClutterAlctor
- * @content_box: (out): computed box occupied by the actor's content
+ * @content_box: computed box occupied by the actor's content
*
* Gets the box within an actor's allocation that contents the content
* of an actor (excluding borders and padding). This is a convenience function
@@ -2211,14 +2211,33 @@ st_theme_node_get_content_box (StThemeNode *node,
const ClutterActorBox *allocation,
ClutterActorBox *content_box)
{
+ double noncontent_left, noncontent_top, noncontent_right, noncontent_bottom;
+ double avail_width, avail_height, content_width, content_height;
+
g_return_if_fail (ST_IS_THEME_NODE (node));
ensure_geometry (node);
- content_box->x1 = (int)(0.5 + node->border_width[ST_SIDE_LEFT]) + node->padding[ST_SIDE_LEFT];
- content_box->y1 = (int)(0.5 + node->border_width[ST_SIDE_TOP]) + node->padding[ST_SIDE_TOP];
- content_box->x2 = allocation->x2 - allocation->x1 - ((int)(0.5 + node->border_width[ST_SIDE_RIGHT]) + node->padding[ST_SIDE_RIGHT]);
- content_box->y2 = allocation->y2 - allocation->y1 - ((int)(0.5 + node->border_width[ST_SIDE_BOTTOM]) + node->padding[ST_SIDE_BOTTOM]);
+ avail_width = allocation->x2 - allocation->x1;
+ avail_height = allocation->y2 - allocation->y1;
+
+ noncontent_left = node->border_width[ST_SIDE_LEFT] + node->padding[ST_SIDE_LEFT];
+ noncontent_top = node->border_width[ST_SIDE_TOP] + node->padding[ST_SIDE_TOP];
+ noncontent_right = node->border_width[ST_SIDE_RIGHT] + node->padding[ST_SIDE_RIGHT];
+ noncontent_bottom = node->border_width[ST_SIDE_BOTTOM] + node->padding[ST_SIDE_BOTTOM];
+
+ content_box->x1 = (int)(0.5 + noncontent_left);
+ content_box->y1 = (int)(0.5 + noncontent_top);
+
+ content_width = avail_width - noncontent_left - noncontent_right;
+ if (content_width < 0)
+ content_width = 0;
+ content_height = avail_height - noncontent_top - noncontent_bottom;
+ if (content_height < 0)
+ content_height = 0;
+
+ content_box->x2 = (int)(0.5 + content_box->x1 + content_width);
+ content_box->y2 = (int)(0.5 + content_box->y1 + content_height);
}
diff --git a/src/st/st-tooltip.c b/src/st/st-tooltip.c
index 5232dbc41..1fbec22e3 100644
--- a/src/st/st-tooltip.c
+++ b/src/st/st-tooltip.c
@@ -148,7 +148,6 @@ st_tooltip_get_preferred_width (ClutterActor *self,
{
StTooltipPrivate *priv = ST_TOOLTIP (self)->priv;
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (self));
- gfloat min_label_w, natural_label_w;
gfloat label_height, arrow_height;
ClutterActor *arrow_image;
@@ -180,13 +179,8 @@ st_tooltip_get_preferred_width (ClutterActor *self,
{
clutter_actor_get_preferred_width (priv->label,
label_height,
- &min_label_w,
- &natural_label_w);
- }
- else
- {
- min_label_w = 0;
- natural_label_w = 0;
+ min_width_p,
+ natural_width_p);
}
st_theme_node_adjust_preferred_width (theme_node, min_width_p, natural_width_p);
diff --git a/src/st/st-widget.c b/src/st/st-widget.c
index 2570ac62c..482d5c04a 100644
--- a/src/st/st-widget.c
+++ b/src/st/st-widget.c
@@ -63,8 +63,11 @@ struct _StWidgetPrivate
gboolean has_tooltip : 1;
gboolean is_style_dirty : 1;
gboolean draw_bg_color : 1;
+ gboolean draw_border_internal : 1;
StTooltip *tooltip;
+
+ StTextDirection direction;
};
/**
@@ -356,25 +359,25 @@ static void
st_widget_real_draw_background (StWidget *self)
{
StWidgetPrivate *priv = self->priv;
+ ClutterActor *actor = CLUTTER_ACTOR (self);
+ ClutterActorBox allocation = { 0, };
+ gfloat w, h;
+ guint8 opacity;
+
+ clutter_actor_get_allocation_box (actor, &allocation);
+ w = allocation.x2 - allocation.x1;
+ h = allocation.y2 - allocation.y1;
+
+ opacity = clutter_actor_get_paint_opacity (actor);
/* Default implementation just draws the background
* colour and the image on top
*/
if (priv->draw_bg_color)
{
- ClutterActor *actor = CLUTTER_ACTOR (self);
- ClutterActorBox allocation = { 0, };
ClutterColor bg_color = priv->bg_color;
- gfloat w, h;
- bg_color.alpha = clutter_actor_get_paint_opacity (actor)
- * bg_color.alpha
- / 255;
-
- clutter_actor_get_allocation_box (actor, &allocation);
-
- w = allocation.x2 - allocation.x1;
- h = allocation.y2 - allocation.y1;
+ bg_color.alpha = opacity * bg_color.alpha / 255;
cogl_set_source_color4ub (bg_color.red,
bg_color.green,
@@ -383,6 +386,76 @@ st_widget_real_draw_background (StWidget *self)
cogl_rectangle (0, 0, w, h);
}
+ if (priv->draw_border_internal)
+ {
+ StThemeNode *node = st_widget_get_theme_node (self);
+ int side;
+ double border_top, border_right, border_bottom, border_left;
+
+ border_top = st_theme_node_get_border_width (node, ST_SIDE_TOP);
+ border_right = st_theme_node_get_border_width (node, ST_SIDE_RIGHT);
+ border_bottom = st_theme_node_get_border_width (node, ST_SIDE_BOTTOM);
+ border_left = st_theme_node_get_border_width (node, ST_SIDE_LEFT);
+
+ for (side = 0; side < 4; side++)
+ {
+ ClutterColor color;
+
+ switch (side)
+ {
+ case ST_SIDE_TOP:
+ if (border_top <= 0)
+ continue;
+ break;
+ case ST_SIDE_RIGHT:
+ if (border_right <= 0)
+ continue;
+ break;
+ case ST_SIDE_BOTTOM:
+ if (border_bottom <= 0)
+ continue;
+ break;
+ case ST_SIDE_LEFT:
+ if (border_left <= 0)
+ continue;
+ break;
+ }
+
+ st_theme_node_get_border_color (node, side, &color);
+
+ color.alpha = (color.alpha * opacity) / 0xff;
+
+ cogl_set_source_color4ub (color.red,
+ color.green,
+ color.blue,
+ color.alpha);
+
+ /* Note top and bottom extend to the ends, left/right
+ * are constrained by them. See comment above about CSS
+ * conformance.
+ */
+ switch (side)
+ {
+ case ST_SIDE_TOP:
+ cogl_rectangle (0, 0,
+ w, border_top);
+ break;
+ case ST_SIDE_RIGHT:
+ cogl_rectangle (w - border_right, border_top,
+ w, h - border_bottom);
+ break;
+ case ST_SIDE_BOTTOM:
+ cogl_rectangle (0, h - border_bottom,
+ w, h);
+ break;
+ case ST_SIDE_LEFT:
+ cogl_rectangle (0, border_top,
+ border_left, h - border_bottom);
+ break;
+ }
+ }
+ }
+
if (priv->border_image)
clutter_actor_paint (priv->border_image);
}
@@ -491,6 +564,7 @@ st_widget_real_style_changed (StWidget *self)
ClutterColor border_color = { 0, };
StSide side;
StCorner corner;
+ gboolean uniform_border_width;
/* application has request this widget is not stylable */
if (!priv->is_stylable)
@@ -520,33 +594,6 @@ st_widget_real_style_changed (StWidget *self)
texture_cache = st_texture_cache_get_default ();
- /* StThemeNode supports different widths and colors for different sides
- * of the border, and different radii for the different corners. We take
- * the different border widths into account when positioning, but our current
- * drawing code (using BigRectangle) can only handle a single width, color,
- * and radius, so we arbitrarily pick the first non-zero width and radius,
- * and use that.
- */
- for (side = ST_SIDE_TOP; side <= ST_SIDE_LEFT; side++)
- {
- double width = st_theme_node_get_border_width (theme_node, side);
- if (width > 0.5)
- {
- border_width = (int)(0.5 + width);
- st_theme_node_get_border_color (theme_node, side, &border_color);
- break;
- }
- }
-
- for (corner = ST_CORNER_TOPLEFT; corner <= ST_CORNER_BOTTOMLEFT; corner++)
- {
- double radius = st_theme_node_get_border_radius (theme_node, corner);
- if (radius > 0.5)
- {
- border_radius = (int)(0.5 + radius);
- break;
- }
- }
/* Rough notes about the relationship of borders and backgrounds in CSS3;
* see http://www.w3.org/TR/css3-background/ for more accurate details.
@@ -565,6 +612,8 @@ st_widget_real_style_changed (StWidget *self)
* zero width or a border image is being used.
*
* Deviations from the above as implemented here:
+ * - Nonuniform border widths combined with a non-zero border radius result
+ * in the border radius being ignored
* - The combination of border image and a non-zero border radius is
* not supported; the background color will be drawn with square
* corners.
@@ -576,6 +625,44 @@ st_widget_real_style_changed (StWidget *self)
* and a single background image above it.
*/
+ /* Check whether all border widths are the same. Also, acquire the
+ * first nonzero border width as well as the border color.
+ */
+ uniform_border_width = TRUE;
+ border_width = st_theme_node_get_border_width (theme_node, ST_SIDE_TOP);
+ if (border_width > 0.5)
+ border_width = (int)(0.5 + border_width);
+ for (side = 0; side < 4; side++)
+ {
+ double width = st_theme_node_get_border_width (theme_node, side);
+ if (width > 0.5)
+ width = (int)(0.5 + width);
+ if (width > 0)
+ {
+ border_width = width;
+ st_theme_node_get_border_color (theme_node, side, &border_color);
+ }
+ if ((int)width != border_width)
+ {
+ uniform_border_width = FALSE;
+ break;
+ }
+ }
+
+ /* Pick the first nonzero border radius, but only if we have a uniform border. */
+ if (uniform_border_width)
+ {
+ for (corner = 0; corner < 4; corner++)
+ {
+ double radius = st_theme_node_get_border_radius (theme_node, corner);
+ if (radius > 0.5)
+ {
+ border_radius = (int)(0.5 + radius);
+ break;
+ }
+ }
+ }
+
border_image = st_theme_node_get_border_image (theme_node);
if (border_image)
{
@@ -607,9 +694,9 @@ st_widget_real_style_changed (StWidget *self)
has_changed = TRUE;
relayout_needed = TRUE;
}
- else if ((border_width > 0 && border_color.alpha != 0) ||
- (border_radius > 0 && priv->bg_color.alpha != 0))
+ else if (border_radius > 0)
{
+ priv->draw_border_internal = FALSE;
priv->draw_bg_color = FALSE;
priv->border_image = g_object_new (BIG_TYPE_RECTANGLE,
"color", &priv->bg_color,
@@ -623,6 +710,19 @@ st_widget_real_style_changed (StWidget *self)
has_changed = TRUE;
relayout_needed = TRUE;
}
+ else if (border_width > 0 && border_color.alpha != 0)
+ {
+ priv->draw_bg_color = TRUE;
+ priv->draw_border_internal = TRUE;
+ has_changed = TRUE;
+ relayout_needed = TRUE;
+ }
+ else if (priv->draw_border_internal)
+ {
+ priv->draw_border_internal = FALSE;
+ has_changed = TRUE;
+ relayout_needed = TRUE;
+ }
bg_file = st_theme_node_get_background_image (theme_node);
if (bg_file != NULL)
@@ -1052,7 +1152,7 @@ st_widget_get_style_pseudo_class (StWidget *actor)
/**
* st_widget_set_style_pseudo_class:
* @actor: a #StWidget
- * @pseudo_class: a new pseudo class string
+ * @pseudo_class: (allow-none): a new pseudo class string
*
* Set the style pseudo class
*/
@@ -1174,6 +1274,40 @@ st_widget_ensure_style (StWidget *widget)
st_widget_recompute_style (widget, NULL);
}
+static StTextDirection default_direction = ST_TEXT_DIRECTION_LTR;
+
+StTextDirection
+st_widget_get_default_direction (void)
+{
+ return default_direction;
+}
+
+void
+st_widget_set_default_direction (StTextDirection dir)
+{
+ g_return_if_fail (dir != ST_TEXT_DIRECTION_NONE);
+
+ default_direction = dir;
+}
+
+StTextDirection
+st_widget_get_direction (StWidget *self)
+{
+ g_return_val_if_fail (ST_IS_WIDGET (self), ST_TEXT_DIRECTION_LTR);
+
+ if (self->priv->direction != ST_TEXT_DIRECTION_NONE)
+ return self->priv->direction;
+ else
+ return default_direction;
+}
+
+void
+st_widget_set_direction (StWidget *self, StTextDirection dir)
+{
+ g_return_if_fail (ST_IS_WIDGET (self));
+ self->priv->direction = dir;
+}
+
/**
* st_widget_get_border_image:
* @actor: A #StWidget
diff --git a/src/st/st-widget.h b/src/st/st-widget.h
index 66f7b0698..bebe28620 100644
--- a/src/st/st-widget.h
+++ b/src/st/st-widget.h
@@ -35,6 +35,12 @@
G_BEGIN_DECLS
+typedef enum {
+ ST_TEXT_DIRECTION_NONE,
+ ST_TEXT_DIRECTION_LTR,
+ ST_TEXT_DIRECTION_RTL
+} StTextDirection;
+
#define ST_TYPE_WIDGET (st_widget_get_type ())
#define ST_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ST_TYPE_WIDGET, StWidget))
#define ST_IS_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ST_TYPE_WIDGET))
@@ -103,6 +109,11 @@ void st_widget_hide_tooltip (StWidget *widget);
void st_widget_ensure_style (StWidget *widget);
+StTextDirection st_widget_get_default_direction (void);
+void st_widget_set_default_direction (StTextDirection dir);
+
+StTextDirection st_widget_get_direction (StWidget *self);
+void st_widget_set_direction (StWidget *self, StTextDirection dir);
/* Only to be used by sub-classes of StWidget */
void st_widget_style_changed (StWidget *widget);
diff --git a/tools/build/gnome-shell-build-setup.sh b/tools/build/gnome-shell-build-setup.sh
index 1f5ddd474..223500353 100755
--- a/tools/build/gnome-shell-build-setup.sh
+++ b/tools/build/gnome-shell-build-setup.sh
@@ -53,12 +53,10 @@ fi
#
# Non-devel packages needed by gnome-shell and its deps:
# glxinfo, gstreamer-plugins-base, gstreamer-plugins-good,
-# python, pygobject, gnome-python (gconf),
-# Xephyr, xeyes*, xlogo*, xterm*, zenity
+# python, pygobject, gnome-python (gconf), gnome-terminal*
+# Xephyr*, zenity
#
-# (*)ed packages are only needed because gnome-shell launches them
-# when running in Xephyr mode, and we should probably change it to use
-# less lame things.
+# (*) only needed for --xephyr
# Can this be simplified? Obvious ways don't handle handle packages
# that have been installed then removed. ('purged' status, e.g.)
@@ -82,7 +80,7 @@ if test x$system = xUbuntu -o x$system = xDebian -o x$system = xLinuxMint ; then
libdbus-glib-1-dev libgconf2-dev libgtk2.0-dev libffi-dev \
libgnome-menu-dev libgnome-desktop-dev librsvg2-dev libwnck-dev libgl1-mesa-dev \
libreadline5-dev mesa-common-dev mesa-utils python-dev python-gconf python-gobject \
- xulrunner-dev xserver-xephyr libcroco3-dev \
+ xulrunner-dev xserver-xephyr gnome-terminal libcroco3-dev \
libgstreamer0.10-dev gstreamer0.10-plugins-base gstreamer0.10-plugins-good \
; do
if ! dpkg_is_installed $pkg; then
@@ -106,7 +104,7 @@ if test x$system = xFedora ; then
gnome-desktop-devel librsvg2-devel libwnck-devel mesa-libGL-devel python-devel pygobject2 \
readline-devel xulrunner-devel libXdamage-devel libcroco-devel \
gstreamer-devel gstreamer-plugins-base gstreamer-plugins-good \
- glx-utils xorg-x11-apps xorg-x11-server-Xephyr xterm zenity \
+ glx-utils xorg-x11-server-Xephyr gnome-terminal zenity \
; do
if ! rpm -q $pkg > /dev/null 2>&1; then
reqd="$pkg $reqd"
@@ -124,7 +122,7 @@ if test x$system = xSUSE ; then
bison flex gnome-doc-utils-devel \
gconf2-devel libffi-devel gnome-desktop-devel librsvg-devel libwnck-devel \
xorg-x11-proto-devel readline-devel mozilla-xulrunner190-devel \
- libcroco-devel xorg-x11-devel xterm xorg-x11 xorg-x11-server-extra \
+ libcroco-devel xorg-x11-devel xorg-x11 xorg-x11-server-extra \
; do
if ! rpm -q $pkg > /dev/null 2>&1; then
reqd="$pkg $reqd"
@@ -144,7 +142,7 @@ if test x$system = xMandrivaLinux ; then
bison flex gnome-common gnome-doc-utils gtk-doc intltool \
libGConf2-devel ffi5-devel libgnomeui2-devel librsvg2-devel \
libwnck-1-devel GL-devel readline-devel libxulrunner-devel \
- libxdamage-devel mesa-demos x11-server-xephyr x11-apps xterm zenity \
+ libxdamage-devel mesa-demos x11-server-xephyr zenity \
libcroco0.6-devel \
; do
if ! rpm -q --whatprovides $pkg > /dev/null 2>&1; then