[gnome-shell] panel: Switch to fully dynamic layout
- From: Colin Walters <walters src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gnome-shell] panel: Switch to fully dynamic layout
- Date: Tue, 11 Aug 2009 17:23:15 +0000 (UTC)
commit e330c5ea17cad7481d485fbd4b2ba5256e3ace09
Author: Colin Walters <walters verbum org>
Date: Tue Aug 11 11:16:25 2009 -0400
panel: Switch to fully dynamic layout
There was lots of fixed positioning in the Panel; now it is completely
dynamic, and width/height is driven from main.js. We still have a
global constant Panel.PANEL_HEIGHT, but this is a big step towards
eliminating it.
Also, this avoids overdraw in the "way too many tray icons" case. The
clock will shift left.
js/ui/main.js | 8 +++
js/ui/overview.js | 4 +-
js/ui/panel.js | 173 +++++++++++++++++++++++++++++++++++++---------------
3 files changed, 132 insertions(+), 53 deletions(-)
---
diff --git a/js/ui/main.js b/js/ui/main.js
index f9b4866..b9e1c86 100644
--- a/js/ui/main.js
+++ b/js/ui/main.js
@@ -77,6 +77,8 @@ function start() {
}
});
+ _relayout();
+
panel.startupAnimation();
let display = global.screen.get_display();
@@ -86,6 +88,12 @@ function start() {
Mainloop.idle_add(_removeUnusedWorkspaces);
}
+function _relayout() {
+ let global = Shell.Global.get();
+ panel.actor.set_size(global.screen_width, Panel.PANEL_HEIGHT);
+ overview.relayout();
+}
+
// metacity-clutter currently uses the same prefs as plain metacity,
// which probably means we'll be starting out with multiple workspaces;
// remove any unused ones. (We do this from an idle handler, because
diff --git a/js/ui/overview.js b/js/ui/overview.js
index c91f6dd..c2ce608 100644
--- a/js/ui/overview.js
+++ b/js/ui/overview.js
@@ -127,8 +127,6 @@ Overview.prototype = {
this._transparentBackground.lower_bottom();
this._paneContainer.lower_bottom();
- this._repositionChildren();
-
this._workspaces = null;
},
@@ -148,7 +146,7 @@ Overview.prototype = {
}
},
- _repositionChildren: function () {
+ relayout: function () {
let global = Shell.Global.get();
let contentHeight = global.screen_height - Panel.PANEL_HEIGHT;
diff --git a/js/ui/panel.js b/js/ui/panel.js
index 4a65733..16d3f68 100644
--- a/js/ui/panel.js
+++ b/js/ui/panel.js
@@ -15,6 +15,8 @@ const Main = imports.ui.main;
const PANEL_HEIGHT = 26;
const TRAY_HEIGHT = PANEL_HEIGHT - 1;
+const DEFAULT_PADDING = 4;
+
const PANEL_BACKGROUND_COLOR = new Clutter.Color();
PANEL_BACKGROUND_COLOR.from_pixel(0x000000ff);
const PANEL_FOREGROUND_COLOR = new Clutter.Color();
@@ -55,26 +57,99 @@ Panel.prototype = {
_init : function() {
let global = Shell.Global.get();
- // Put the background under the panel within a group.
- this.actor = new Clutter.Group();
-
- // backBox contains the panel background and the clock.
- let backBox = new Big.Box({ width: global.screen_width,
- height: PANEL_HEIGHT,
- backgroundColor: PANEL_BACKGROUND_COLOR,
- x_align: Big.BoxAlignment.CENTER });
- this.actor.add_actor(backBox);
-
- let box = new Big.Box({ x: 0,
- y: 0,
- height: PANEL_HEIGHT,
- width: global.screen_width,
- orientation: Big.BoxOrientation.HORIZONTAL,
- spacing: 4 });
-
- this.button = new Button.Button("Activities", PANEL_BUTTON_COLOR, PRESSED_BUTTON_BACKGROUND_COLOR, PANEL_FOREGROUND_COLOR, true, null, PANEL_HEIGHT, DEFAULT_FONT);
-
- box.append(this.button.button, Big.BoxPackFlags.NONE);
+ this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
+ background_color: PANEL_BACKGROUND_COLOR
+ });
+ this._leftBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
+ y_align: Big.BoxAlignment.CENTER,
+ padding_right: DEFAULT_PADDING });
+ this._centerBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
+ y_align: Big.BoxAlignment.CENTER });
+ this._rightBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
+ y_align: Big.BoxAlignment.CENTER,
+ padding_left: DEFAULT_PADDING });
+
+ /* This box container ensures that the centerBox is positioned in the *absolute*
+ * center, but can be pushed aside if necessary. */
+ this._boxContainer = new Shell.GenericContainer();
+ this.actor.append(this._boxContainer, Big.BoxPackFlags.EXPAND);
+ this._boxContainer.add_actor(this._leftBox);
+ this._boxContainer.add_actor(this._centerBox);
+ this._boxContainer.add_actor(this._rightBox);
+ this._boxContainer.connect('get-preferred-width', Lang.bind(this, function(box, forHeight, alloc) {
+ let children = box.get_children();
+ for (let i = 0; i < children.length; i++) {
+ let [childMin, childNatural] = children[i].get_preferred_width(forHeight);
+ alloc.min_size += childMin;
+ alloc.natural_size += childNatural;
+ }
+ }));
+ this._boxContainer.connect('get-preferred-height', Lang.bind(this, function(box, forWidth, alloc) {
+ let children = box.get_children();
+ for (let i = 0; i < children.length; i++) {
+ let [childMin, childNatural] = children[i].get_preferred_height(forWidth);
+ if (childMin > alloc.min_size)
+ alloc.min_size = childMin;
+ if (childNatural > alloc.natural_size)
+ alloc.natural_size = childNatural;
+ }
+ }));
+ this._boxContainer.connect('allocate', Lang.bind(this, function(container, box, flags) {
+ let allocWidth = box.x2 - box.x1;
+ let allocHeight = box.y2 - box.y1;
+ let [leftMinWidth, leftNaturalWidth] = this._leftBox.get_preferred_width(-1);
+ let [centerMinWidth, centerNaturalWidth] = this._centerBox.get_preferred_width(-1);
+ let [rightMinWidth, rightNaturalWidth] = this._rightBox.get_preferred_width(-1);
+ let leftWidth, centerWidth, rightWidth;
+ if (allocWidth < (leftNaturalWidth + centerNaturalWidth + rightNaturalWidth)) {
+ leftWidth = leftMinWidth;
+ centerWidth = centerMinWidth;
+ rightWidth = rightMinWidth;
+ } else {
+ leftWidth = leftNaturalWidth;
+ centerWidth = centerNaturalWidth;
+ rightWidth = rightNaturalWidth;
+ }
+
+ let x;
+ let childBox = new Clutter.ActorBox();
+ childBox.x1 = box.x1;
+ childBox.y1 = box.y1;
+ childBox.x2 = x = childBox.x1 + leftWidth;
+ childBox.y2 = box.y2;
+ this._leftBox.allocate(childBox, flags);
+
+ let centerNaturalX = Math.floor((box.x2 - box.x1) / 2 - (centerWidth / 2));
+ /* Check left side */
+ if (x < centerNaturalX) {
+ /* We didn't overflow the left, use the natural. */
+ x = centerNaturalX;
+ }
+ /* Check right side */
+ if (x + centerWidth > (box.x2 - rightWidth)) {
+ x = box.x2 - rightWidth - centerWidth;
+ }
+ childBox = new Clutter.ActorBox();
+ childBox.x1 = x;
+ childBox.y1 = box.y1;
+ childBox.x2 = x = childBox.x1 + centerWidth;
+ childBox.y2 = box.y2;
+ this._centerBox.allocate(childBox, flags);
+
+ childBox = new Clutter.ActorBox();
+ childBox.x1 = box.x2 - rightWidth;
+ childBox.y1 = box.y1;
+ childBox.x2 = box.x2;
+ childBox.y2 = box.y2;
+ this._rightBox.allocate(childBox, flags);
+ }));
+
+ /* left side */
+
+ this.button = new Button.Button("Activities", PANEL_BUTTON_COLOR, PRESSED_BUTTON_BACKGROUND_COLOR,
+ PANEL_FOREGROUND_COLOR, true, null, PANEL_HEIGHT, DEFAULT_FONT);
+
+ this._leftBox.append(this.button.button, Big.BoxPackFlags.NONE);
let hotCorner = new Clutter.Rectangle({ width: 1,
height: 1,
@@ -89,43 +164,22 @@ Panel.prototype = {
hotCorner.connect('button-release-event',
Lang.bind(this, this._onHotCornerTriggered));
- box.add_actor(hotCorner);
+ this._leftBox.append(hotCorner, Big.BoxPackFlags.FIXED);
- 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 statusbutton = new Button.Button(statusbox,
- PANEL_BUTTON_COLOR,
- PRESSED_BUTTON_BACKGROUND_COLOR,
- PANEL_FOREGROUND_COLOR,
- true, null, PANEL_HEIGHT);
- statusbutton.button.connect('button-press-event', function (b, e) {
- statusmenu.toggle(e);
- return false;
- });
- box.append(statusbutton.button, Big.BoxPackFlags.END);
- // We get a deactivated event when the popup disappears
- this._statusmenu.connect('deactivated', function (sm) {
- statusbutton.release();
- });
+ /* center */
this._clock = new Clutter.Text({ font_name: DEFAULT_FONT,
color: PANEL_FOREGROUND_COLOR,
text: "" });
- let clockbox = new Big.Box({ y_align: Big.BoxAlignment.CENTER,
- padding_left: 4,
- padding_right: 4 });
- clockbox.append(this._clock, Big.BoxPackFlags.NONE);
- backBox.append(clockbox, Big.BoxPackFlags.EXPAND);
+ this._centerBox.append(this._clock, Big.BoxPackFlags.NONE);
+
+ /* right */
// The tray icons live in trayBox within trayContainer.
// The trayBox is hidden when there are no tray icons.
let trayContainer = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
y_align: Big.BoxAlignment.START });
- box.append(trayContainer, Big.BoxPackFlags.END);
+ this._rightBox.append(trayContainer, Big.BoxPackFlags.NONE);
let trayBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
height: TRAY_HEIGHT,
padding: TRAY_PADDING,
@@ -164,6 +218,27 @@ 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 statusbutton = new Button.Button(statusbox,
+ PANEL_BUTTON_COLOR,
+ PRESSED_BUTTON_BACKGROUND_COLOR,
+ PANEL_FOREGROUND_COLOR,
+ true, null, PANEL_HEIGHT);
+ statusbutton.button.connect('button-press-event', function (b, e) {
+ statusmenu.toggle(e);
+ return false;
+ });
+ this._rightBox.append(statusbutton.button, Big.BoxPackFlags.NONE);
+ // We get a deactivated event when the popup disappears
+ this._statusmenu.connect('deactivated', function (sm) {
+ statusbutton.release();
+ });
+
// TODO: decide what to do with the rest of the panel in the Overview mode (make it fade-out, become non-reactive, etc.)
// We get into the Overview mode on button-press-event as opposed to button-release-event because eventually we'll probably
// have the Overview act like a menu that allows the user to release the mouse on the activity the user wants
@@ -176,9 +251,7 @@ Panel.prototype = {
Main.overview.connect('showing', Lang.bind(this.button, this.button.pressIn));
Main.overview.connect('hiding', Lang.bind(this.button, this.button.release));
- this.actor.add_actor(box);
-
- Main.chrome.addActor(this.actor, box);
+ Main.chrome.addActor(this.actor);
Main.chrome.setVisibleInOverview(this.actor, true);
// Start the clock
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]