Redo tabs => spaces indentation change to not lose manual indentation

Revert most JS changes in commit:

    Fri Nov 28 20:12:20 2008 +0000
    Convert all JS style to be uniform, add Eclipse settings bits

Instead, just add 'indent-tabs-mode: nil' to the mode lines and convert
tabs to spaces. The indentation no longer exactly matches the Eclipse
settings, since they differ in some ways from the style we are trying
to achieve.

svn path=/trunk/; revision=97
This commit is contained in:
Owen Taylor 2008-12-01 19:51:43 +00:00
parent 12720e2c90
commit 7b471645f4
7 changed files with 1049 additions and 1045 deletions

View File

@ -1,4 +1,4 @@
/* -*- mode: js2; js2-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil -*- */
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Signals = imports.signals;
const Clutter = imports.gi.Clutter;
@ -10,31 +10,31 @@ const Tidy = imports.gi.Tidy;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
//TODO - move this into GConf once we're not a plugin anymore
//but have taken over metacity
//This list is taken from GNOME Online popular applications
//http://online.gnome.org/applications
//but with nautilus removed
// TODO - move this into GConf once we're not a plugin anymore
// but have taken over metacity
// This list is taken from GNOME Online popular applications
// http://online.gnome.org/applications
// but with nautilus removed
const DEFAULT_APPLICATIONS = [
'mozilla-firefox.desktop',
'gnome-terminal.desktop',
'evolution.desktop',
'evince.desktop',
'gedit.desktop',
'mozilla-thunderbird.desktop',
'totem.desktop',
'gnome-file-roller.desktop',
'rhythmbox.desktop',
'epiphany.desktop',
'xchat.desktop',
'openoffice.org-1.9-writer.desktop',
'emacs.desktop',
'gnome-system-monitor.desktop',
'openoffice.org-1.9-calc.desktop',
'eclipse.desktop',
'openoffice.org-1.9-impress.desktop',
'vncviewer.desktop'
];
'mozilla-firefox.desktop',
'gnome-terminal.desktop',
'evolution.desktop',
'evince.desktop',
'gedit.desktop',
'mozilla-thunderbird.desktop',
'totem.desktop',
'gnome-file-roller.desktop',
'rhythmbox.desktop',
'epiphany.desktop',
'xchat.desktop',
'openoffice.org-1.9-writer.desktop',
'emacs.desktop',
'gnome-system-monitor.desktop',
'openoffice.org-1.9-calc.desktop',
'eclipse.desktop',
'openoffice.org-1.9-impress.desktop',
'vncviewer.desktop'
];
const APPDISPLAY_NAME_COLOR = new Clutter.Color();
APPDISPLAY_NAME_COLOR.from_pixel(0xffffffff);
@ -49,304 +49,305 @@ const APPDISPLAY_HEIGHT = 50;
const APPDISPLAY_PADDING = 4;
function AppDisplayItem(node, width) {
this._init(node, width);
this._init(node, width);
}
AppDisplayItem.prototype = {
_init: function(appinfo, width) {
let me = this;
this._appinfo = appinfo;
_init: function(appinfo, width) {
let me = this;
this._appinfo = appinfo;
let name = appinfo.get_name();
let name = appinfo.get_name();
let icontheme = Gtk.IconTheme.get_default();
let icontheme = Gtk.IconTheme.get_default();
this._group = new Clutter.Group({reactive: true,
width: width,
height: APPDISPLAY_HEIGHT});
this._group.connect('button-press-event', function(group, e) {
me.emit('activate');
return true;
});
this._bg = new Clutter.Rectangle({ color: APPDISPLAY_BACKGROUND_COLOR,
x: 0, y: 0, width: width, height: APPDISPLAY_HEIGHT });
this._group.add_actor(this._bg);
this._group = new Clutter.Group({reactive: true,
width: width,
height: APPDISPLAY_HEIGHT});
this._group.connect('button-press-event', function(group, e) {
me.emit('activate');
return true;
});
this._bg = new Clutter.Rectangle({ color: APPDISPLAY_BACKGROUND_COLOR,
x: 0, y: 0,
width: width, height: APPDISPLAY_HEIGHT });
this._group.add_actor(this._bg);
this._icon = new Clutter.Texture({ width: 48, height: 48, x: 0, y: 0 });
let gicon = appinfo.get_icon();
let path = null;
if (gicon != null) {
let iconinfo = icontheme.lookup_by_gicon(gicon, 48, Gtk.IconLookupFlags.NO_SVG);
if (iconinfo)
path = iconinfo.get_filename();
}
this._icon = new Clutter.Texture({ width: 48, height: 48, x: 0, y: 0 });
let gicon = appinfo.get_icon();
let path = null;
if (gicon != null) {
let iconinfo = icontheme.lookup_by_gicon(gicon, 48, Gtk.IconLookupFlags.NO_SVG);
if (iconinfo)
path = iconinfo.get_filename();
}
if (path)
this._icon.set_from_file(path);
this._group.add_actor(this._icon);
if (path)
this._icon.set_from_file(path);
this._group.add_actor(this._icon);
let comment = appinfo.get_description();
let text_width = width - me._icon.width + 4;
this._name = new Clutter.Label({ color: APPDISPLAY_NAME_COLOR,
font_name: "Sans 14px",
width: text_width,
ellipsize: Pango.EllipsizeMode.END,
text: name,
x: this._icon.width + 4,
y: 0});
this._group.add_actor(this._name);
this._comment = new Clutter.Label({ color: APPDISPLAY_COMMENT_COLOR,
font_name: "Sans 12px",
width: text_width,
ellipsize: Pango.EllipsizeMode.END,
text: comment,
x: this._name.x,
y: this._name.height + 4})
this._group.add_actor(this._comment);
this.actor = this._group;
},
launch: function() {
this._appinfo.launch([], null);
},
appinfo: function () {
return this._appinfo;
},
markSelected: function(isSelected) {
let color;
if (isSelected)
color = APPDISPLAY_SELECTED_BACKGROUND_COLOR;
else
color = APPDISPLAY_BACKGROUND_COLOR;
this._bg.color = color;
}
};
let comment = appinfo.get_description();
let text_width = width - me._icon.width + 4;
this._name = new Clutter.Label({ color: APPDISPLAY_NAME_COLOR,
font_name: "Sans 14px",
width: text_width,
ellipsize: Pango.EllipsizeMode.END,
text: name,
x: this._icon.width + 4,
y: 0});
this._group.add_actor(this._name);
this._comment = new Clutter.Label({ color: APPDISPLAY_COMMENT_COLOR,
font_name: "Sans 12px",
width: text_width,
ellipsize: Pango.EllipsizeMode.END,
text: comment,
x: this._name.x,
y: this._name.height + 4})
this._group.add_actor(this._comment);
this.actor = this._group;
},
launch: function() {
this._appinfo.launch([], null);
},
appinfo: function () {
return this._appinfo;
},
markSelected: function(isSelected) {
let color;
if (isSelected)
color = APPDISPLAY_SELECTED_BACKGROUND_COLOR;
else
color = APPDISPLAY_BACKGROUND_COLOR;
this._bg.color = color;
}
}
Signals.addSignalMethods(AppDisplayItem.prototype);
function AppDisplay(x, y, width, height) {
this._init(x, y, width, height);
this._init(x, y, width, height);
}
AppDisplay.prototype = {
_init : function(x, y, width, height) {
let me = this;
let global = Shell.Global.get();
this._search = '';
this._x = x;
this._y = y;
this._width = width;
this._height = height;
this._appmonitor = new Shell.AppMonitor();
this._appsStale = true;
this._appmonitor.connect('changed', function(mon) {
me._appsStale = true;
});
this._grid = new Tidy.Grid({x: x, y: y, width: width, height: height});
global.stage.add_actor(this._grid);
this._appset = {}; // Map<appid, appinfo>
this._displayed = {} // Map<appid, AppDisplay>
this._selectedIndex = -1;
this._max_items = this._height / (APPDISPLAY_HEIGHT + APPDISPLAY_PADDING);
},
_init : function(x, y, width, height) {
let me = this;
let global = Shell.Global.get();
this._search = '';
this._x = x;
this._y = y;
this._width = width;
this._height = height;
this._appmonitor = new Shell.AppMonitor();
this._appsStale = true;
this._appmonitor.connect('changed', function(mon) {
me._appsStale = true;
});
this._grid = new Tidy.Grid({x: x, y: y, width: width, height: height});
global.stage.add_actor(this._grid);
this._appset = {}; // Map<appid, appinfo>
this._displayed = {}; // Map<appid, AppDisplay>
this._selectedIndex = -1;
this._max_items = this._height / (APPDISPLAY_HEIGHT + APPDISPLAY_PADDING);
},
_refreshCache: function() {
let me = this;
_refreshCache: function() {
let me = this;
if (!this._appsStale)
return;
for (id in this._displayed)
this._displayed[id].destroy();
this._appset = {};
this._displayed = {};
this._selectedIndex = -1;
let apps = Gio.app_info_get_all();
for (let i = 0; i < apps.length; i++) {
let appinfo = apps[i];
let appid = appinfo.get_id();
this._appset[appid] = appinfo;
}
this._appsStale = false;
},
_removeItem: function(appid) {
let item = this._displayed[appid];
let group = item.actor;
group.destroy();
delete this._displayed[appid];
},
_removeAll: function() {
for (appid in this._displayed)
this._removeItem(appid);
},
_setDefaultList: function() {
this._removeAll();
let added = 0;
for (let i = 0; i < DEFAULT_APPLICATIONS.length && added < this._max_items; i++) {
let appid = DEFAULT_APPLICATIONS[i];
let appinfo = this._appset[appid];
if (appinfo) {
this._filterAdd(appid);
added += 1;
}
}
},
_getNDisplayed: function() {
// Is there a better way to do .size() ?
let c = 0; for (i in this._displayed) { c += 1; };
return c;
},
_filterAdd: function(appid) {
let me = this;
let appinfo = this._appset[appid];
let name = appinfo.get_name();
let index = this._getNDisplayed();
let appdisplay = new AppDisplayItem(appinfo, this._width);
appdisplay.connect('activate', function() {
appdisplay.launch();
me.emit('activated');
});
let group = appdisplay.actor;
this._grid.add_actor(group);
this._displayed[appid] = appdisplay;
},
_filterRemove: function(appid) {
// In the future, do some sort of fade out or other effect here
let item = this._displayed[appid];
this._removeItem(item);
},
_appinfoMatches: function(appinfo, search) {
if (search == null || search == '')
return true;
let name = appinfo.get_name().toLowerCase();
if (name.indexOf(search) >= 0)
return true;
let description = appinfo.get_description();
if (description) {
description = description.toLowerCase();
if (description.indexOf(search) >= 0)
return true;
}
let exec = appinfo.get_executable().toLowerCase();
if (exec.indexOf(search) >= 0)
return true;
return false;
},
_sortApps: function(appids) {
let me = this;
return appids.sort(function (a,b) {
let appA = me._appset[a];
let appB = me._appset[b];
return appA.get_name().localeCompare(appB.get_name());
});
},
_doSearchFilter: function() {
this._removeAll();
let matchedApps = [];
for (appid in this._appset) {
if (matchedApps.length >= this._max_items)
break;
if (this._displayed[appid])
continue;
let app = this._appset[appid];
if (this._appinfoMatches(app, this._search))
matchedApps.push(appid);
}
this._sortApps(matchedApps);
for (let i = 0; i < matchedApps.length; i++) {
this._filterAdd(matchedApps[i]);
}
},
_redisplay: function() {
this._refreshCache();
if (!this._search)
this._setDefaultList();
else
this._doSearchFilter();
},
setSearch: function(text) {
this._search = text.toLowerCase();
this._redisplay();
},
_findDisplayedByIndex: function(index) {
let displayedActors = this._grid.get_children();
let actor = displayedActors[index];
return this._findDisplayedByActor(actor);
},
_findDisplayedByActor: function(actor) {
for (appid in this._displayed) {
let item = this._displayed[appid];
if (item.actor == actor) {
return item;
if (!this._appsStale)
return;
for (id in this._displayed)
this._displayed[id].destroy();
this._appset = {};
this._displayed = {};
this._selectedIndex = -1;
let apps = Gio.app_info_get_all();
for (let i = 0; i < apps.length; i++) {
let appinfo = apps[i];
let appid = appinfo.get_id();
this._appset[appid] = appinfo;
}
}
return null;
},
this._appsStale = false;
},
searchActivate: function() {
if (this._selectedIndex != -1) {
let selected = this._findDisplayedByIndex(this._selectedIndex);
selected.launch();
_removeItem: function(appid) {
let item = this._displayed[appid];
let group = item.actor;
group.destroy();
delete this._displayed[appid];
},
_removeAll: function() {
for (appid in this._displayed)
this._removeItem(appid);
},
_setDefaultList: function() {
this._removeAll();
let added = 0;
for (let i = 0; i < DEFAULT_APPLICATIONS.length && added < this._max_items; i++) {
let appid = DEFAULT_APPLICATIONS[i];
let appinfo = this._appset[appid];
if (appinfo) {
this._filterAdd(appid);
added += 1;
}
}
},
_getNDisplayed: function() {
// Is there a better way to do .size() ?
let c = 0; for (i in this._displayed) { c += 1; };
return c;
},
_filterAdd: function(appid) {
let me = this;
let appinfo = this._appset[appid];
let name = appinfo.get_name();
let index = this._getNDisplayed();
let appdisplay = new AppDisplayItem(appinfo, this._width);
appdisplay.connect('activate', function() {
appdisplay.launch();
me.emit('activated');
});
let group = appdisplay.actor;
this._grid.add_actor(group);
this._displayed[appid] = appdisplay;
},
_filterRemove: function(appid) {
// In the future, do some sort of fade out or other effect here
let item = this._displayed[appid];
this._removeItem(item);
},
_appinfoMatches: function(appinfo, search) {
if (search == null || search == '')
return true;
let name = appinfo.get_name().toLowerCase();
if (name.indexOf(search) >= 0)
return true;
let description = appinfo.get_description();
if (description) {
description = description.toLowerCase();
if (description.indexOf(search) >= 0)
return true;
}
let exec = appinfo.get_executable().toLowerCase();
if (exec.indexOf(search) >= 0)
return true;
return false;
},
_sortApps: function(appids) {
let me = this;
return appids.sort(function (a,b) {
let appA = me._appset[a];
let appB = me._appset[b];
return appA.get_name().localeCompare(appB.get_name());
});
},
_doSearchFilter: function() {
this._removeAll();
let matchedApps = [];
for (appid in this._appset) {
if (matchedApps.length >= this._max_items)
break;
if (this._displayed[appid])
continue;
let app = this._appset[appid];
if (this._appinfoMatches(app, this._search))
matchedApps.push(appid);
}
this._sortApps(matchedApps);
for (let i = 0; i < matchedApps.length; i++) {
this._filterAdd(matchedApps[i]);
}
},
_redisplay: function() {
this._refreshCache();
if (!this._search)
this._setDefaultList();
else
this._doSearchFilter();
},
setSearch: function(text) {
this._search = text.toLowerCase();
this._redisplay();
},
_findDisplayedByIndex: function(index) {
let displayedActors = this._grid.get_children();
let actor = displayedActors[index];
return this._findDisplayedByActor(actor);
},
_findDisplayedByActor: function(actor) {
for (appid in this._displayed) {
let item = this._displayed[appid];
if (item.actor == actor) {
return item;
}
}
return null;
},
searchActivate: function() {
if (this._selectedIndex != -1) {
let selected = this._findDisplayedByIndex(this._selectedIndex);
selected.launch();
this.emit('activated');
return;
}
let displayedActors = this._grid.get_children();
if (displayedActors.length != 1)
return;
let selectedActor = displayedActors[0];
let selectedMenuItem = this._findDisplayedByActor(selectedActor);
selectedMenuItem.launch();
this.emit('activated');
return;
}
let displayedActors = this._grid.get_children();
if (displayedActors.length != 1)
return;
let selectedActor = displayedActors[0];
let selectedMenuItem = this._findDisplayedByActor(selectedActor);
selectedMenuItem.launch();
this.emit('activated');
},
},
_selectIndex: function(index) {
if (this._selectedIndex != -1) {
let prev = this._findDisplayedByIndex(this._selectedIndex);
log("demarking " + prev);
prev.markSelected(false);
_selectIndex: function(index) {
if (this._selectedIndex != -1) {
let prev = this._findDisplayedByIndex(this._selectedIndex);
log("demarking " + prev);
prev.markSelected(false);
}
this._selectedIndex = index;
let item = this._findDisplayedByIndex(index);
log("marking " + item);
item.markSelected(true);
},
selectUp: function() {
let prev = this._selectedIndex-1;
if (prev < 0)
return;
this._selectIndex(prev);
},
selectDown: function() {
let next = this._selectedIndex+1;
let nDisplayed = this._getNDisplayed();
if (next >= nDisplayed)
return;
this._selectIndex(next);
},
show: function() {
this._redisplay();
this._grid.show();
},
hide: function() {
this._grid.hide();
}
this._selectedIndex = index;
let item = this._findDisplayedByIndex(index);
log("marking " + item);
item.markSelected(true);
},
};
selectUp: function() {
let prev = this._selectedIndex-1;
if (prev < 0)
return;
this._selectIndex(prev);
},
selectDown: function() {
let next = this._selectedIndex+1;
let nDisplayed = this._getNDisplayed();
if (next >= nDisplayed)
return;
this._selectIndex(next);
},
show: function() {
this._redisplay();
this._grid.show();
},
hide: function() {
this._grid.hide();
}
}
Signals.addSignalMethods(AppDisplay.prototype);

View File

@ -1,4 +1,4 @@
/* -*- mode: js2; js2-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil -*- */
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Tweener = imports.tweener.tweener;
@ -9,7 +9,7 @@ DEFAULT_BUTTON_COLOR.from_pixel(0xeeddccff);
const DEFAULT_PRESSED_BUTTON_COLOR = new Clutter.Color();
DEFAULT_PRESSED_BUTTON_COLOR.from_pixel(0xccbbaaff);
//Time for animation making the button darker
// Time for animation making the button darker
const ANIMATION_TIME = 0.3;
const NO_OPACITY = 0;
@ -23,95 +23,95 @@ function Button(text, buttonColor, pressedButtonColor, staysPressed, minWidth, m
}
Button.prototype = {
_init : function(text, buttonColor, pressedButtonColor, staysPressed, minWidth, minHeight) {
let me = this;
this._buttonColor = buttonColor
if (buttonColor == null)
this._buttonColor = DEFAULT_BUTTON_COLOR;
_init : function(text, buttonColor, pressedButtonColor, staysPressed, minWidth, minHeight) {
let me = this;
this._pressedButtonColor = pressedButtonColor
if (pressedButtonColor == null)
this._pressedButtonColor = DEFAULT_PRESSED_BUTTON_COLOR;
this._buttonColor = buttonColor
if (buttonColor == null)
this._buttonColor = DEFAULT_BUTTON_COLOR;
if (staysPressed == null)
staysPressed = false;
if (minWidth == null)
minWidth = 0;
if (minHeight == null)
minHeight = 0;
this._pressedButtonColor = pressedButtonColor
if (pressedButtonColor == null)
this._pressedButtonColor = DEFAULT_PRESSED_BUTTON_COLOR;
// if staysPressed is true, this.active will be true past the first release of a button, untill a subsequent one (the button
// is unpressed) or untill release() is called explicitly
this._active = false;
this._isBetweenPressAndRelease = false;
this._mouseIsOverButton = false;
if (staysPressed == null)
staysPressed = false;
if (minWidth == null)
minWidth = 0;
if (minHeight == null)
minHeight = 0;
this.button = new Clutter.Group({reactive: true});
this._background = new Clutter.Rectangle({ color: this._buttonColor});
this._pressedBackground = new Clutter.Rectangle({ color: this._pressedButtonColor, opacity: NO_OPACITY});
this._label = new Clutter.Label({ font_name: "Sans Bold 16px",
text: text});
this._label.set_position(5, 5);
let backgroundWidth = Math.max(this._label.get_width()+10, minWidth);
let backgroundHeight = Math.max(this._label.get_height()+10, minHeight);
this._background.set_width(backgroundWidth)
this._background.set_height(backgroundHeight)
this._pressedBackground.set_width(backgroundWidth)
this._pressedBackground.set_height(backgroundHeight)
this.button.add_actor(this._background);
this.button.add_actor(this._pressedBackground);
this.button.add_actor(this._label);
this.button.connect('button-press-event',
function(o, event) {
me._isBetweenPressAndRelease = true;
Tweener.addTween(me._pressedBackground,
{ time: ANIMATION_TIME,
opacity: FULL_OPACITY,
transition: "linear"
});
return false;
});
this.button.connect('button-release-event',
function(o, event) {
me._isBetweenPressAndRelease = false;
if (!staysPressed || me._active) {
me.release();
} else {
me._active = true;
}
return false;
});
this.button.connect('enter-event',
function(o, event) {
me._mouseIsOverButton = true;
if (!me._active) {
Tweener.removeTweens(me._pressedBackground);
me._pressedBackground.set_opacity(PARTIAL_OPACITY);
}
return false;
});
this.button.connect('leave-event',
function(o, event) {
me._isBetweenPressAndRelease = false;
me._mouseIsOverButton = false;
if (!me._active) {
Tweener.removeTweens(me._pressedBackground);
me._pressedBackground.set_opacity(NO_OPACITY);
}
return false;
});
},
release : function() {
if (!this._isBetweenPressAndRelease) {
// if staysPressed is true, this.active will be true past the first release of a button, untill a subsequent one (the button
// is unpressed) or untill release() is called explicitly
this._active = false;
Tweener.removeTweens(this._pressedBackground);
if (this._mouseIsOverButton) {
this._pressedBackground.set_opacity(PARTIAL_OPACITY);
} else {
this._pressedBackground.set_opacity(NO_OPACITY);
this._isBetweenPressAndRelease = false;
this._mouseIsOverButton = false;
this.button = new Clutter.Group({reactive: true});
this._background = new Clutter.Rectangle({ color: this._buttonColor});
this._pressedBackground = new Clutter.Rectangle({ color: this._pressedButtonColor, opacity: NO_OPACITY});
this._label = new Clutter.Label({ font_name: "Sans Bold 16px",
text: text});
this._label.set_position(5, 5);
let backgroundWidth = Math.max(this._label.get_width()+10, minWidth);
let backgroundHeight = Math.max(this._label.get_height()+10, minHeight);
this._background.set_width(backgroundWidth)
this._background.set_height(backgroundHeight)
this._pressedBackground.set_width(backgroundWidth)
this._pressedBackground.set_height(backgroundHeight)
this.button.add_actor(this._background);
this.button.add_actor(this._pressedBackground);
this.button.add_actor(this._label);
this.button.connect('button-press-event',
function(o, event) {
me._isBetweenPressAndRelease = true;
Tweener.addTween(me._pressedBackground,
{ time: ANIMATION_TIME,
opacity: FULL_OPACITY,
transition: "linear"
});
return false;
});
this.button.connect('button-release-event',
function(o, event) {
me._isBetweenPressAndRelease = false;
if (!staysPressed || me._active) {
me.release();
} else {
me._active = true;
}
return false;
});
this.button.connect('enter-event',
function(o, event) {
me._mouseIsOverButton = true;
if (!me._active) {
Tweener.removeTweens(me._pressedBackground);
me._pressedBackground.set_opacity(PARTIAL_OPACITY);
}
return false;
});
this.button.connect('leave-event',
function(o, event) {
me._isBetweenPressAndRelease = false;
me._mouseIsOverButton = false;
if (!me._active) {
Tweener.removeTweens(me._pressedBackground);
me._pressedBackground.set_opacity(NO_OPACITY);
}
return false;
});
},
release : function() {
if (!this._isBetweenPressAndRelease) {
this._active = false;
Tweener.removeTweens(this._pressedBackground);
if (this._mouseIsOverButton) {
this._pressedBackground.set_opacity(PARTIAL_OPACITY);
} else {
this._pressedBackground.set_opacity(NO_OPACITY);
}
}
}
}
}
};

View File

@ -1,4 +1,4 @@
/* -*- mode: js2; js2-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil -*- */
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Shell = imports.gi.Shell;
@ -18,67 +18,67 @@ let overlay = null;
let run_dialog = null;
let wm = null;
//The "FrameTicker" object is an object used to feed new frames to Tweener
//so it can update values and redraw. The default frame ticker for
//Tweener just uses a simple timeout at a fixed frame rate and has no idea
//of "catching up" by dropping frames.
//We substitute it with custom frame ticker here that connects Tweener to
//a Clutter.TimeLine. Now, Clutter.Timeline itself isn't a whole lot more
//sophisticated than a simple timeout at a fixed frame rate, but at least
//it knows how to drop frames. (See HippoAnimationManager for a more
//sophisticated view of continous time updates; even better is to pay
//attention to the vertical vblank and sync to that when possible.)
// The "FrameTicker" object is an object used to feed new frames to Tweener
// so it can update values and redraw. The default frame ticker for
// Tweener just uses a simple timeout at a fixed frame rate and has no idea
// of "catching up" by dropping frames.
//
// We substitute it with custom frame ticker here that connects Tweener to
// a Clutter.TimeLine. Now, Clutter.Timeline itself isn't a whole lot more
// sophisticated than a simple timeout at a fixed frame rate, but at least
// it knows how to drop frames. (See HippoAnimationManager for a more
// sophisticated view of continous time updates; even better is to pay
// attention to the vertical vblank and sync to that when possible.)
//
function ClutterFrameTicker() {
this._init();
}
ClutterFrameTicker.prototype = {
TARGET_FRAME_RATE : 60,
TARGET_FRAME_RATE : 60,
_init : function() {
// We don't have a finite duration; tweener will tell us to stop
// when we need to stop, so use 1000 seconds as "infinity"
this._timeline = new Clutter.Timeline({ fps: this.TARGET_FRAME_RATE,
duration: 1000*1000 });
this._frame = 0;
_init : function() {
// We don't have a finite duration; tweener will tell us to stop
// when we need to stop, so use 1000 seconds as "infinity"
this._timeline = new Clutter.Timeline({ fps: this.TARGET_FRAME_RATE,
duration: 1000*1000 });
this._frame = 0;
let me = this;
this._timeline.connect('new-frame',
let me = this;
this._timeline.connect('new-frame',
function(timeline, frame) {
me._onNewFrame(frame);
});
},
me._onNewFrame(frame);
});
},
_onNewFrame : function(frame) {
// Unfortunately the interface to to send a new frame to tweener
// is a simple "next frame" and there is no provision for signaling
// that frames have been skipped or just telling it the new time.
// But what it actually does internally is just:
//
// _currentTime += 1000/_ticker.FRAME_RATE;
//
// So by dynamically adjusting the value of FRAME_RATE we can trick
// it into dealing with dropped frames.
_onNewFrame : function(frame) {
// Unfortunately the interface to to send a new frame to tweener
// is a simple "next frame" and there is no provision for signaling
// that frames have been skipped or just telling it the new time.
// But what it actually does internally is just:
//
// _currentTime += 1000/_ticker.FRAME_RATE;
//
// So by dynamically adjusting the value of FRAME_RATE we can trick
// it into dealing with dropped frames.
let delta = frame - this._frame;
if (delta == 0)
this.FRAME_RATE = this.TARGET_FRAME_RATE;
else
this.FRAME_RATE = this.TARGET_FRAME_RATE / delta;
this._frame = frame;
this.emit('prepare-frame');
},
let delta = frame - this._frame;
if (delta == 0)
this.FRAME_RATE = this.TARGET_FRAME_RATE;
else
this.FRAME_RATE = this.TARGET_FRAME_RATE / delta;
this._frame = frame;
this.emit('prepare-frame');
},
start : function() {
this._timeline.start();
},
start : function() {
this._timeline.start();
},
stop : function() {
this._timeline.stop();
this._frame = 0;
}
stop : function() {
this._timeline.stop();
this._frame = 0;
}
};
Signals.addSignalMethods(ClutterFrameTicker.prototype);
@ -121,9 +121,9 @@ function start() {
wm = new WindowManager.WindowManager();
}
//Used to go into a mode where all keyboard and mouse input goes to
//the stage. Returns true if we successfully grabbed the keyboard and
//went modal, false otherwise
// Used to go into a mode where all keyboard and mouse input goes to
// the stage. Returns true if we successfully grabbed the keyboard and
// went modal, false otherwise
function startModal() {
let global = Shell.Global.get();

View File

@ -1,4 +1,4 @@
/* -*- mode: js2; js2-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil -*- */
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Signals = imports.signals;
const Mainloop = imports.mainloop;
@ -23,27 +23,27 @@ SIDESHOW_SEARCH_BG_COLOR.from_pixel(0xffffffff);
const SIDESHOW_TEXT_COLOR = new Clutter.Color();
SIDESHOW_TEXT_COLOR.from_pixel(0xffffffff);
//Time for initial animation going into overlay mode
// Time for initial animation going into overlay mode
const ANIMATION_TIME = 0.5;
//How much to scale the desktop down by in overlay mode
// How much to scale the desktop down by in overlay mode
const DESKTOP_SCALE = 0.75;
//Windows are slightly translucent in the overlay mode
// Windows are slightly translucent in the overlay mode
const WINDOW_OPACITY = 0.9 * 255;
//Define a layout scheme for small window counts. For larger
//counts we fall back to an algorithm. We need more schemes here
//unless we have a really good algorithm.
//Each triplet is [xCenter, yCenter, scale] where the scale
//is relative to the width of the desktop.
// Define a layout scheme for small window counts. For larger
// counts we fall back to an algorithm. We need more schemes here
// unless we have a really good algorithm.
//
// Each triplet is [xCenter, yCenter, scale] where the scale
// is relative to the width of the desktop.
const POSITIONS = {
1: [[0.5, 0.5, 0.8]],
2: [[0.25, 0.5, 0.4], [0.75, 0.5, 0.4]],
3: [[0.25, 0.25, 0.33], [0.75, 0.25, 0.33], [0.5, 0.75, 0.33]],
4: [[0.25, 0.25, 0.33], [0.75, 0.25, 0.33], [0.75, 0.75, 0.33], [0.25, 0.75, 0.33]],
5: [[0.165, 0.25, 0.28], [0.495, 0.25, 0.28], [0.825, 0.25, 0.28], [0.25, 0.75, 0.4], [0.75, 0.75, 0.4]]
1: [[0.5, 0.5, 0.8]],
2: [[0.25, 0.5, 0.4], [0.75, 0.5, 0.4]],
3: [[0.25, 0.25, 0.33], [0.75, 0.25, 0.33], [0.5, 0.75, 0.33]],
4: [[0.25, 0.25, 0.33], [0.75, 0.25, 0.33], [0.75, 0.75, 0.33], [0.25, 0.75, 0.33]],
5: [[0.165, 0.25, 0.28], [0.495, 0.25, 0.28], [0.825, 0.25, 0.28], [0.25, 0.75, 0.4], [0.75, 0.75, 0.4]]
};
function Sideshow(width) {
@ -51,95 +51,95 @@ function Sideshow(width) {
}
Sideshow.prototype = {
_init : function(width) {
let me = this;
_init : function(width) {
let me = this;
let global = Shell.Global.get();
this._group = new Clutter.Group();
this._group.hide();
global.stage.add_actor(this._group);
let icontheme = Gtk.IconTheme.get_default();
let rect = new Clutter.Rectangle({ color: SIDESHOW_SEARCH_BG_COLOR,
x: SIDESHOW_PAD,
y: Panel.PANEL_HEIGHT + SIDESHOW_PAD,
width: width,
height: 24});
this._group.add_actor(rect);
let global = Shell.Global.get();
this._group = new Clutter.Group();
this._group.hide();
global.stage.add_actor(this._group);
let icontheme = Gtk.IconTheme.get_default();
let rect = new Clutter.Rectangle({ color: SIDESHOW_SEARCH_BG_COLOR,
x: SIDESHOW_PAD,
y: Panel.PANEL_HEIGHT + SIDESHOW_PAD,
width: width,
height: 24});
this._group.add_actor(rect);
let searchIconTexture = new Clutter.Texture({ x: SIDESHOW_PAD + 2,
y: rect.y + 2 });
let searchIconPath = icontheme.lookup_icon('gtk-find', 16, 0).get_filename();
searchIconTexture.set_from_file(searchIconPath);
this._group.add_actor(searchIconTexture);
let searchIconTexture = new Clutter.Texture({ x: SIDESHOW_PAD + 2,
y: rect.y + 2 });
let searchIconPath = icontheme.lookup_icon('gtk-find', 16, 0).get_filename();
searchIconTexture.set_from_file(searchIconPath);
this._group.add_actor(searchIconTexture);
this._searchEntry = new Clutter.Entry({
font_name: "Sans 14px",
x: searchIconTexture.x
+ searchIconTexture.width + 4,
y: searchIconTexture.y,
width: rect.width - (searchIconTexture.x),
height: searchIconTexture.height});
this._group.add_actor(this._searchEntry);
global.stage.set_key_focus(this._searchEntry);
this._searchQueued = false;
this._searchActive = false;
this._searchEntry.connect('notify::text', function (se, prop) {
if (me._searchQueued)
return;
Mainloop.timeout_add(250, function() {
let text = me._searchEntry.text;
me._searchQueued = false;
me._searchActive = text != '';
me._appdisplay.setSearch(text);
this._searchEntry = new Clutter.Entry({
font_name: "Sans 14px",
x: searchIconTexture.x
+ searchIconTexture.width + 4,
y: searchIconTexture.y,
width: rect.width - (searchIconTexture.x),
height: searchIconTexture.height});
this._group.add_actor(this._searchEntry);
global.stage.set_key_focus(this._searchEntry);
this._searchQueued = false;
this._searchActive = false;
this._searchEntry.connect('notify::text', function (se, prop) {
if (me._searchQueued)
return;
Mainloop.timeout_add(250, function() {
let text = me._searchEntry.text;
me._searchQueued = false;
me._searchActive = text != '';
me._appdisplay.setSearch(text);
return false;
});
});
this._searchEntry.connect('activate', function (se) {
if (!me._searchActive)
return false;
me._appdisplay.searchActivate();
return true;
});
this._searchEntry.connect('key-press-event', function (se, e) {
let code = e.get_code();
log("code: " + code);
if (code == 111) {
me._appdisplay.selectUp();
return true;
} else if (code == 116) {
me._appdisplay.selectDown();
return true;
}
return false;
});
});
this._searchEntry.connect('activate', function (se) {
if (!me._searchActive)
return false;
me._appdisplay.searchActivate();
return true;
});
this._searchEntry.connect('key-press-event', function (se, e) {
let code = e.get_code();
log("code: " + code);
if (code == 111) {
me._appdisplay.selectUp();
return true;
} else if (code == 116) {
me._appdisplay.selectDown();
return true;
}
return false;
});
let appsText = new Clutter.Label({ color: SIDESHOW_TEXT_COLOR,
font_name: "Sans Bold 14px",
text: "Applications",
x: SIDESHOW_PAD,
y: this._searchEntry.y + this._searchEntry.height + 10,
height: 16});
this._group.add_actor(appsText);
let appsText = new Clutter.Label({ color: SIDESHOW_TEXT_COLOR,
font_name: "Sans Bold 14px",
text: "Applications",
x: SIDESHOW_PAD,
y: this._searchEntry.y + this._searchEntry.height + 10,
height: 16});
this._group.add_actor(appsText);
let menuY = appsText.y + appsText.height + 6;
this._appdisplay = new AppDisplay.AppDisplay(SIDESHOW_PAD,
menuY, width, global.screen_height - menuY);
let menuY = appsText.y + appsText.height + 6;
this._appdisplay = new AppDisplay.AppDisplay(SIDESHOW_PAD,
menuY, width, global.screen_height - menuY);
/* Proxy the activated signal */
this._appdisplay.connect('activated', function(appdisplay) {
me.emit('activated');
});
},
/* Proxy the activated signal */
this._appdisplay.connect('activated', function(appdisplay) {
me.emit('activated');
});
},
show: function() {
this._group.show();
this._appdisplay.show();
},
show: function() {
this._group.show();
this._appdisplay.show();
},
hide: function() {
this._group.hide();
this._appdisplay.hide();
}
hide: function() {
this._group.hide();
this._appdisplay.hide();
}
};
Signals.addSignalMethods(Sideshow.prototype);
@ -148,252 +148,254 @@ function Overlay() {
}
Overlay.prototype = {
_init : function() {
let me = this;
_init : function() {
let me = this;
let global = Shell.Global.get();
let global = Shell.Global.get();
this._group = new Clutter.Group();
this.visible = false;
this._group = new Clutter.Group();
this.visible = false;
let background = new Clutter.Rectangle({ color: OVERLAY_BACKGROUND_COLOR,
reactive: true,
x: 0,
y: Panel.PANEL_HEIGHT,
width: global.screen_width,
height: global.screen_width - Panel.PANEL_HEIGHT });
this._group.add_actor(background);
let background = new Clutter.Rectangle({ color: OVERLAY_BACKGROUND_COLOR,
reactive: true,
x: 0,
y: Panel.PANEL_HEIGHT,
width: global.screen_width,
height: global.screen_width - Panel.PANEL_HEIGHT });
this._group.add_actor(background);
this._group.hide();
global.overlay_group.add_actor(this._group);
this._group.hide();
global.overlay_group.add_actor(this._group);
this._windowClones = [];
// TODO - recalculate everything when desktop size changes
this._recalculateSize();
// TODO - recalculate everything when desktop size changes
this._recalculateSize();
this._sideshow = new Sideshow(this._desktopX - 10);
this._sideshow.connect('activated', function(sideshow) {
// TODO - have some sort of animation/effect while
// transitioning to the new app. We definitely need
// startup-notification integration at least.
me._deactivate();
});
},
this._sideshow = new Sideshow(this._desktopX - 10);
this._sideshow.connect('activated', function(sideshow) {
// TODO - have some sort of animation/effect while
// transitioning to the new app. We definitely need
// startup-notification integration at least.
me._deactivate();
});
},
_recalculateSize: function () {
let global = Shell.Global.get();
let screenWidth = global.screen_width;
let screenHeight = global.screen_height;
// The desktop windows are shown on top of a scaled down version of the
// desktop. This is positioned at the right side of the screen
this._desktopWidth = screenWidth * DESKTOP_SCALE;
this._desktopHeight = screenHeight * DESKTOP_SCALE;
this._desktopX = screenWidth - this._desktopWidth - 10;
this._desktopY = Panel.PANEL_HEIGHT + (screenHeight - this._desktopHeight - Panel.PANEL_HEIGHT) / 2;
},
_recalculateSize: function () {
let global = Shell.Global.get();
let screenWidth = global.screen_width;
let screenHeight = global.screen_height;
// The desktop windows are shown on top of a scaled down version of the
// desktop. This is positioned at the right side of the screen
this._desktopWidth = screenWidth * DESKTOP_SCALE;
this._desktopHeight = screenHeight * DESKTOP_SCALE;
this._desktopX = screenWidth - this._desktopWidth - 10;
this._desktopY = Panel.PANEL_HEIGHT + (screenHeight - this._desktopHeight - Panel.PANEL_HEIGHT) / 2;
},
show : function() {
if (this.visible)
return;
this.visible = true;
show : function() {
if (this.visible)
return;
let global = Shell.Global.get();
this.visible = true;
let windows = global.get_windows();
let desktopWindow = null;
let global = Shell.Global.get();
this._recalculateSize();
let windows = global.get_windows();
let desktopWindow = null;
for (let i = 0; i < windows.length; i++)
if (windows[i].get_window_type() == Meta.WindowType.DESKTOP)
desktopWindow = windows[i];
this._recalculateSize();
// If a file manager is displaying desktop icons, there will be a desktop window.
// This window will have the size of the whole desktop. When such window is not present
// (e.g. when the preference for showing icons on the desktop is disabled by the user
// or we are running inside a Xephyr window), we should create a desktop rectangle
// to serve as the background.
if (desktopWindow)
this._createDesktopClone(desktopWindow);
else
this._createDesktopRectangle();
for (let i = 0; i < windows.length; i++)
if (windows[i].get_window_type() == Meta.WindowType.DESKTOP)
desktopWindow = windows[i];
// Count the total number of windows so we know what layout scheme to use
let numberOfWindows = 0;
for (let i = 0; i < windows.length; i++) {
let w = windows[i];
if (w == desktopWindow || w.is_override_redirect())
continue;
// If a file manager is displaying desktop icons, there will be a desktop window.
// This window will have the size of the whole desktop. When such window is not present
// (e.g. when the preference for showing icons on the desktop is disabled by the user
// or we are running inside a Xephyr window), we should create a desktop rectangle
// to serve as the background.
if (desktopWindow)
this._createDesktopClone(desktopWindow);
else
this._createDesktopRectangle();
numberOfWindows++;
// Count the total number of windows so we know what layout scheme to use
let numberOfWindows = 0;
for (let i = 0; i < windows.length; i++) {
let w = windows[i];
if (w == desktopWindow || w.is_override_redirect())
continue;
numberOfWindows++;
}
// Now create actors for all the desktop windows. Do it in
// reverse order so that the active actor ends up on top
let windowIndex = 0;
for (let i = windows.length - 1; i >= 0; i--) {
let w = windows[i];
if (w == desktopWindow || w.is_override_redirect())
continue;
this._createWindowClone(w, numberOfWindows - windowIndex - 1, numberOfWindows);
windowIndex++;
}
this._sideshow.show();
// All the the actors in the window group are completely obscured,
// hiding the group holding them while the overlay is displayed greatly
// increases performance of the overlay especially when there are many
// windows visible.
//
// If we switched to displaying the actors in the overlay rather than
// clones of them, this would obviously no longer be necessary.
global.window_group.hide()
this._group.show();
},
hide : function() {
if (!this.visible)
return;
let global = Shell.Global.get();
this.visible = false;
global.window_group.show()
this._group.hide();
for (let i = 0; i < this._windowClones.length; i++) {
this._windowClones[i].destroy();
}
this._sideshow.hide();
this._windowClones = [];
},
_createDesktopClone : function(w) {
let clone = new Clutter.CloneTexture({ parent_texture: w.get_texture(),
reactive: true,
x: 0,
y: 0 });
this._addDesktop(clone);
},
_createDesktopRectangle : function() {
let global = Shell.Global.get();
// In the case when we have a desktop window from the file manager, its height is
// full-screen, i.e. it includes the height of the panel, so we should not subtract
// the height of the panel from global.screen_height here either to have them show
// up identically.
// We are also using (0,0) coordinates in both cases which makes the background
// window animate out from behind the panel.
let desktopRectangle = new Clutter.Rectangle({ color: global.stage.color,
reactive: true,
x: 0,
y: 0,
width: global.screen_width,
height: global.screen_height });
this._addDesktop(desktopRectangle);
},
_addDesktop : function(desktop) {
let me = this;
this._windowClones.push(desktop);
this._group.add_actor(desktop);
// Since the right side only moves a little bit (the width of padding
// we add) it looks less jittery to put the anchor there.
desktop.move_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
Tweener.addTween(desktop,
{ x: this._desktopX + this._desktopWidth,
y: this._desktopY,
scale_x: DESKTOP_SCALE,
scale_y: DESKTOP_SCALE,
time: ANIMATION_TIME,
transition: "easeOutQuad"
});
desktop.connect("button-press-event",
function() {
me._deactivate();
});
},
// windowIndex == 0 => top in stacking order
_computeWindowPosition : function(windowIndex, numberOfWindows) {
if (numberOfWindows in POSITIONS)
return POSITIONS[numberOfWindows][windowIndex];
// If we don't have a predefined scheme for this window count, overlap the windows
// along the diagonal of the desktop (improve this!)
let fraction = Math.sqrt(1/numberOfWindows);
// The top window goes at the lower right - this is different from the
// fixed position schemes where the windows are in "reading order"
// and the top window goes at the upper left.
let pos = (numberOfWindows - windowIndex - 1) / (numberOfWindows - 1);
let xCenter = (fraction / 2) + (1 - fraction) * pos;
let yCenter = xCenter;
return [xCenter, yCenter, fraction];
},
_createWindowClone : function(w, windowIndex, numberOfWindows) {
let me = this;
// We show the window using "clones" of the texture .. separate
// actors that mirror the original actors for the window. For
// animation purposes, it may be better to actually move the
// original actors about instead.
let clone = new Clutter.CloneTexture({ parent_texture: w.get_texture(),
reactive: true,
x: w.x,
y: w.y });
let [xCenter, yCenter, fraction] = this._computeWindowPosition(windowIndex, numberOfWindows);
let desiredSize = this._desktopWidth * fraction;
xCenter = this._desktopX + xCenter * this._desktopWidth;
yCenter = this._desktopY + yCenter * this._desktopHeight;
let size = clone.width;
if (clone.height > size)
size = clone.height;
// Never scale up
let scale = desiredSize / size;
if (scale > 1)
scale = 1;
this._group.add_actor(clone);
this._windowClones.push(clone);
Tweener.addTween(clone,
{ x: xCenter - 0.5 * scale * w.width,
y: yCenter - 0.5 * scale * w.height,
scale_x: scale,
scale_y: scale,
time: ANIMATION_TIME,
opacity: WINDOW_OPACITY,
transition: "easeOutQuad"
});
clone.connect("button-press-event",
function(clone, event) {
me._activateWindow(w, event.get_time());
});
},
_activateWindow : function(w, time) {
this._deactivate();
w.get_meta_window().activate(time);
},
_deactivate : function() {
Main.hide_overlay();
}
// Now create actors for all the desktop windows. Do it in
// reverse order so that the active actor ends up on top
let windowIndex = 0;
for (let i = windows.length - 1; i >= 0; i--) {
let w = windows[i];
if (w == desktopWindow || w.is_override_redirect())
continue;
this._createWindowClone(w, numberOfWindows - windowIndex - 1, numberOfWindows);
windowIndex++;
}
this._sideshow.show();
// All the the actors in the window group are completely obscured,
// hiding the group holding them while the overlay is displayed greatly
// increases performance of the overlay especially when there are many
// windows visible.
//
// If we switched to displaying the actors in the overlay rather than
// clones of them, this would obviously no longer be necessary.
global.window_group.hide()
this._group.show();
},
hide : function() {
if (!this.visible)
return;
let global = Shell.Global.get();
this.visible = false;
global.window_group.show()
this._group.hide();
for (let i = 0; i < this._windowClones.length; i++) {
this._windowClones[i].destroy();
}
this._sideshow.hide();
this._windowClones = [];
},
_createDesktopClone : function(w) {
let clone = new Clutter.CloneTexture({ parent_texture: w.get_texture(),
reactive: true,
x: 0,
y: 0 });
this._addDesktop(clone);
},
_createDesktopRectangle : function() {
let global = Shell.Global.get();
// In the case when we have a desktop window from the file manager, its height is
// full-screen, i.e. it includes the height of the panel, so we should not subtract
// the height of the panel from global.screen_height here either to have them show
// up identically.
// We are also using (0,0) coordinates in both cases which makes the background
// window animate out from behind the panel.
let desktopRectangle = new Clutter.Rectangle({ color: global.stage.color,
reactive: true,
x: 0,
y: 0,
width: global.screen_width,
height: global.screen_height });
this._addDesktop(desktopRectangle);
},
_addDesktop : function(desktop) {
let me = this;
this._windowClones.push(desktop);
this._group.add_actor(desktop);
// Since the right side only moves a little bit (the width of padding
// we add) it looks less jittery to put the anchor there.
desktop.move_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
Tweener.addTween(desktop,
{ x: this._desktopX + this._desktopWidth,
y: this._desktopY,
scale_x: DESKTOP_SCALE,
scale_y: DESKTOP_SCALE,
time: ANIMATION_TIME,
transition: "easeOutQuad"
});
desktop.connect("button-press-event",
function() {
me._deactivate();
});
},
//windowIndex == 0 => top in stacking order
_computeWindowPosition : function(windowIndex, numberOfWindows) {
if (numberOfWindows in POSITIONS)
return POSITIONS[numberOfWindows][windowIndex];
// If we don't have a predefined scheme for this window count, overlap the windows
// along the diagonal of the desktop (improve this!)
let fraction = Math.sqrt(1/numberOfWindows);
// The top window goes at the lower right - this is different from the
// fixed position schemes where the windows are in "reading order"
// and the top window goes at the upper left.
let pos = (numberOfWindows - windowIndex - 1) / (numberOfWindows - 1);
let xCenter = (fraction / 2) + (1 - fraction) * pos;
let yCenter = xCenter;
return [xCenter, yCenter, fraction];
},
_createWindowClone : function(w, windowIndex, numberOfWindows) {
let me = this;
// We show the window using "clones" of the texture .. separate
// actors that mirror the original actors for the window. For
// animation purposes, it may be better to actually move the
// original actors about instead.
let clone = new Clutter.CloneTexture({ parent_texture: w.get_texture(),
reactive: true,
x: w.x,
y: w.y });
let [xCenter, yCenter, fraction] = this._computeWindowPosition(windowIndex, numberOfWindows);
let desiredSize = this._desktopWidth * fraction;
xCenter = this._desktopX + xCenter * this._desktopWidth;
yCenter = this._desktopY + yCenter * this._desktopHeight;
let size = clone.width;
if (clone.height > size)
size = clone.height;
// Never scale up
let scale = desiredSize / size;
if (scale > 1)
scale = 1;
this._group.add_actor(clone);
this._windowClones.push(clone);
Tweener.addTween(clone,
{ x: xCenter - 0.5 * scale * w.width,
y: yCenter - 0.5 * scale * w.height,
scale_x: scale,
scale_y: scale,
time: ANIMATION_TIME,
opacity: WINDOW_OPACITY,
transition: "easeOutQuad"
});
clone.connect("button-press-event",
function(clone, event) {
me._activateWindow(w, event.get_time());
});
},
_activateWindow : function(w, time) {
this._deactivate();
w.get_meta_window().activate(time);
},
_deactivate : function() {
Main.hide_overlay();
}
};

View File

@ -1,4 +1,4 @@
/* -*- mode: js2; js2-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil -*- */
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Mainloop = imports.mainloop;
@ -21,123 +21,123 @@ function Panel() {
}
Panel.prototype = {
_init : function() {
let global = Shell.Global.get();
_init : function() {
let global = Shell.Global.get();
this._group = new Clutter.Group();
this._group = new Clutter.Group();
let background = new Clutter.Rectangle({ color: PANEL_BACKGROUND_COLOR,
reactive: true,
width: global.screen_width+2,
height: PANEL_HEIGHT+1,
border_width: 1});
background.set_position(-1, -1);
this._group.add_actor(background);
let background = new Clutter.Rectangle({ color: PANEL_BACKGROUND_COLOR,
reactive: true,
width: global.screen_width+2,
height: PANEL_HEIGHT+1,
border_width: 1});
background.set_position(-1, -1);
this._group.add_actor(background);
this.button = new Button.Button("Activities", PANEL_BACKGROUND_COLOR, PRESSED_BUTTON_BACKGROUND_COLOR, true, null, PANEL_HEIGHT-1);
this.button = new Button.Button("Activities", PANEL_BACKGROUND_COLOR, PRESSED_BUTTON_BACKGROUND_COLOR, true, null, PANEL_HEIGHT-1);
this._group.add_actor(this.button.button);
this._group.add_actor(this.button.button);
this._grid = new Tidy.Grid({ height: TRAY_HEIGHT,
valign: 0.5,
end_align: true,
column_gap: 2 })
this._group.add_actor(this._grid);
this._grid = new Tidy.Grid({ height: TRAY_HEIGHT,
valign: 0.5,
end_align: true,
column_gap: 2 })
this._group.add_actor(this._grid);
this._clock = new Clutter.Label({ font_name: "Sans Bold 16px",
text: "" });
this._grid.add_actor(this._clock);
this._clock = new Clutter.Label({ font_name: "Sans Bold 16px",
text: "" });
this._grid.add_actor(this._clock);
// Setting the anchor point at top right (north east) makes that portion of the
// grid positioned at the position specified below.
this._grid.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
this._grid.set_position(global.screen_width - 2, (PANEL_HEIGHT - TRAY_HEIGHT) / 2);
// Setting the anchor point at top right (north east) makes that portion of the
// grid positioned at the position specified below.
this._grid.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
this._grid.set_position(global.screen_width - 2, (PANEL_HEIGHT - TRAY_HEIGHT) / 2);
this._traymanager = new Shell.TrayManager({ bg_color: PANEL_BACKGROUND_COLOR });
let me = this;
// the anchor point needs to be updated each time the height/width of the content might have changed, because
// it doesn't get updated on its own
this._traymanager.connect('tray-icon-added',
this._traymanager = new Shell.TrayManager({ bg_color: PANEL_BACKGROUND_COLOR });
let me = this;
// the anchor point needs to be updated each time the height/width of the content might have changed, because
// it doesn't get updated on its own
this._traymanager.connect('tray-icon-added',
function(o, icon) {
me._grid.add_actor(icon);
/* bump the clock back to the end */
me._grid.remove_actor(me._clock);
me._grid.add_actor(me._clock);
me._grid.move_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
});
this._traymanager.connect('tray-icon-removed',
me._grid.add_actor(icon);
/* bump the clock back to the end */
me._grid.remove_actor(me._clock);
me._grid.add_actor(me._clock);
me._grid.move_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
});
this._traymanager.connect('tray-icon-removed',
function(o, icon) {
me._grid.remove_actor(icon);
me._grid.move_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
});
this._traymanager.manage_stage(global.stage);
me._grid.remove_actor(icon);
me._grid.move_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
});
this._traymanager.manage_stage(global.stage);
// TODO: decide what to do with the rest of the panel in the overlay mode (make it fade-out, become non-reactive, etc.)
// We get into the overlay mode on button-press-event as opposed to button-release-event because eventually we'll probably
// have the overlay act like a menu that allows the user to release the mouse on the activity the user wants
// to switch to.
this.button.button.connect('button-press-event',
// TODO: decide what to do with the rest of the panel in the overlay mode (make it fade-out, become non-reactive, etc.)
// We get into the overlay mode on button-press-event as opposed to button-release-event because eventually we'll probably
// have the overlay act like a menu that allows the user to release the mouse on the activity the user wants
// to switch to.
this.button.button.connect('button-press-event',
function(o, event) {
if (Main.overlay.visible)
Main.hide_overlay();
else
Main.show_overlay();
if (Main.overlay.visible)
Main.hide_overlay();
else
Main.show_overlay();
return true;
});
return true;
});
this._setStruts();
global.screen.connect('notify::n-workspaces',
this._setStruts();
global.screen.connect('notify::n-workspaces',
function() {
me._setStruts();
});
me._setStruts();
});
global.stage.add_actor(this._group);
global.stage.add_actor(this._group);
this._updateClock();
this._startClock();
},
this._updateClock();
this._startClock();
},
// Struts determine the area along each side of the screen that is reserved
// and not available to applications
_setStruts: function() {
let global = Shell.Global.get();
// Struts determine the area along each side of the screen that is reserved
// and not available to applications
_setStruts: function() {
let global = Shell.Global.get();
let struts = [
new Meta.Strut({
rect: {
x: 0,
y: 0,
width: global.screen_width,
height: PANEL_HEIGHT
},
side: Meta.Direction.TOP
})
];
let struts = [
new Meta.Strut({
rect: {
x: 0,
y: 0,
width: global.screen_width,
height: PANEL_HEIGHT
},
side: Meta.Direction.TOP
})
];
let screen = global.screen;
for (let i = 0; i < screen.n_workspaces; i++) {
let workspace = screen.get_workspace_by_index(i);
workspace.set_builtin_struts(struts);
let screen = global.screen;
for (let i = 0; i < screen.n_workspaces; i++) {
let workspace = screen.get_workspace_by_index(i);
workspace.set_builtin_struts(struts);
}
},
_startClock: function() {
let me = this;
// TODO: this makes the clock updated every 60 seconds, but not necessarily on the minute, so it is inaccurate
Mainloop.timeout_add_seconds(60,
function() {
me._updateClock();
return true;
});
},
_updateClock: function() {
this._clock.set_text(new Date().toLocaleFormat("%H:%M"));
return true;
},
overlayHidden: function() {
this.button.release();
}
},
_startClock: function() {
let me = this;
// TODO: this makes the clock updated every 60 seconds, but not necessarily on the minute, so it is inaccurate
Mainloop.timeout_add_seconds(60,
function() {
me._updateClock();
return true;
});
},
_updateClock: function() {
this._clock.set_text(new Date().toLocaleFormat("%H:%M"));
return true;
},
overlayHidden: function() {
this.button.release();
}
};

View File

@ -1,4 +1,4 @@
/* -*- mode: js2; js2-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil -*- */
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Signals = imports.signals;
const Shell = imports.gi.Shell;
@ -23,110 +23,111 @@ function RunDialog() {
};
RunDialog.prototype = {
_init : function() {
let global = Shell.Global.get();
_init : function() {
let global = Shell.Global.get();
// All actors are inside _group. We create it initially
// hidden then show it in show()
this._group = new Clutter.Group({ visible: false });
global.stage.add_actor(this._group);
// All actors are inside _group. We create it initially
// hidden then show it in show()
this._group = new Clutter.Group({ visible: false });
global.stage.add_actor(this._group);
this._overlay = new Clutter.Rectangle({ color: OVERLAY_COLOR,
width: global.screen_width,
height: global.screen_height,
border_width: 0,
reactive: true });
this._group.add_actor(this._overlay);
this._overlay = new Clutter.Rectangle({ color: OVERLAY_COLOR,
width: global.screen_width,
height: global.screen_height,
border_width: 0,
reactive: true });
this._group.add_actor(this._overlay);
let boxGroup = new Clutter.Group();
boxGroup.set_position((global.screen_width - BOX_WIDTH) / 2,
(global.screen_height - BOX_HEIGHT) / 2);
this._group.add_actor(boxGroup);
let boxGroup = new Clutter.Group();
boxGroup.set_position((global.screen_width - BOX_WIDTH) / 2,
(global.screen_height - BOX_HEIGHT) / 2);
this._group.add_actor(boxGroup);
let box = new Clutter.Rectangle({ color: BOX_BACKGROUND_COLOR,
reactive: false,
width: BOX_WIDTH,
height: BOX_HEIGHT,
border_width: 0 });
boxGroup.add_actor(box);
let box = new Clutter.Rectangle({ color: BOX_BACKGROUND_COLOR,
reactive: false,
width: BOX_WIDTH,
height: BOX_HEIGHT,
border_width: 0 });
boxGroup.add_actor(box);
let label = new Clutter.Label({ color: BOX_TEXT_COLOR,
font_name: '18px Sans',
text: 'Please enter a command:' });
label.set_position(6, 6);
boxGroup.add_actor(label);
let label = new Clutter.Label({ color: BOX_TEXT_COLOR,
font_name: '18px Sans',
text: 'Please enter a command:' });
label.set_position(6, 6);
boxGroup.add_actor(label);
this._entry = new Clutter.Entry({ color: BOX_TEXT_COLOR,
font_name: '20px Sans Bold',
reactive: true,
text: '',
entry_padding: 0,
width: BOX_WIDTH - 12,
height: BOX_HEIGHT - 12 });
// TODO: Implement relative positioning using Tidy.
this._entry.set_position(6, 30);
boxGroup.add_actor(this._entry);
this._entry = new Clutter.Entry({ color: BOX_TEXT_COLOR,
font_name: '20px Sans Bold',
reactive: true,
text: '',
entry_padding: 0,
width: BOX_WIDTH - 12,
height: BOX_HEIGHT - 12 });
// TODO: Implement relative positioning using Tidy.
this._entry.set_position(6, 30);
boxGroup.add_actor(this._entry);
let me = this;
let me = this;
this._entry.connect('activate', function (o, e) {
me.hide();
me._run(o.get_text());
return false;
});
},
_run : function(command) {
if (command) {
var p = new Shell.Process({'args' : [command]});
try {
p.run();
} catch (e) {
// TODO: Give the user direct feedback.
log('Could not run command ' + command + '.');
}
}
this.emit('run');
},
show : function() {
let me = this;
if (this._group.visible) // Already shown
return false;
if (!Main.startModal())
return false;
this._group.show_all();
this._entry.connect('key-press-event', function(o, e) {
if (e.get_code() == 9) {
this._entry.connect('activate', function (o, e) {
me.hide();
me.emit('cancel');
return true;
} else
me._run(o.get_text());
return false;
});
});
let global = Shell.Global.get();
global.stage.set_key_focus(this._entry);
},
return true;
},
_run : function(command) {
if (command) {
var p = new Shell.Process({'args' : [command]});
try {
p.run();
} catch (e) {
// TODO: Give the user direct feedback.
log('Could not run command ' + command + '.');
}
}
hide : function() {
if (!this._group.visible)
return;
this.emit('run');
},
this._group.hide();
Main.endModal();
},
show : function() {
let me = this;
destroy : function(){
this.hide();
this._group.destroy();
}
if (this._group.visible) // Already shown
return false;
if (!Main.startModal())
return false;
this._group.show_all();
this._entry.connect('key-press-event', function(o, e) {
if (e.get_code() == 9) {
me.hide();
me.emit('cancel');
return true;
} else
return false;
});
let global = Shell.Global.get();
global.stage.set_key_focus(this._entry);
return true;
},
hide : function() {
if (!this._group.visible)
return;
this._group.hide();
Main.endModal();
},
destroy : function(){
this.hide();
this._group.destroy();
}
};
Signals.addSignalMethods(RunDialog.prototype);

View File

@ -1,4 +1,4 @@
/* -*- mode: js2; js2-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil -*- */
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Mainloop = imports.mainloop;
@ -15,111 +15,111 @@ function WindowManager() {
}
WindowManager.prototype = {
_init : function() {
let me = this;
_init : function() {
let me = this;
this._global = Shell.Global.get();
this._shellwm = this._global.window_manager;
this._global = Shell.Global.get();
this._shellwm = this._global.window_manager;
this._switchData = null;
this._shellwm.connect('switch-workspace',
this._switchData = null;
this._shellwm.connect('switch-workspace',
function(o, from, to, direction) {
let actors = me._shellwm.get_switch_workspace_actors();
me.switchWorkspace(actors, from, to, direction);
});
this._shellwm.connect('kill-switch-workspace',
let actors = me._shellwm.get_switch_workspace_actors();
me.switchWorkspace(actors, from, to, direction);
});
this._shellwm.connect('kill-switch-workspace',
function(o) {
me.switchWorkspaceDone();
});
},
me.switchWorkspaceDone();
});
},
switchWorkspace : function(windows, from, to, direction) {
/* @direction is the direction that the "camera" moves, so the
* screen contents have to move one screen's worth in the
* opposite direction.
*/
let xDest = 0, yDest = 0;
switchWorkspace : function(windows, from, to, direction) {
/* @direction is the direction that the "camera" moves, so the
* screen contents have to move one screen's worth in the
* opposite direction.
*/
let xDest = 0, yDest = 0;
if (direction == Meta.MotionDirection.UP ||
if (direction == Meta.MotionDirection.UP ||
direction == Meta.MotionDirection.UP_LEFT ||
direction == Meta.MotionDirection.UP_RIGHT)
yDest = this._global.screen_height;
else if (direction == Meta.MotionDirection.DOWN ||
yDest = this._global.screen_height;
else if (direction == Meta.MotionDirection.DOWN ||
direction == Meta.MotionDirection.DOWN_LEFT ||
direction == Meta.MotionDirection.DOWN_RIGHT)
yDest = -this._global.screen_height;
yDest = -this._global.screen_height;
if (direction == Meta.MotionDirection.LEFT ||
if (direction == Meta.MotionDirection.LEFT ||
direction == Meta.MotionDirection.UP_LEFT ||
direction == Meta.MotionDirection.DOWN_LEFT)
xDest = this._global.screen_width;
else if (direction == Meta.MotionDirection.RIGHT ||
direction == Meta.MotionDirection.UP_RIGHT ||
direction == Meta.MotionDirection.DOWN_RIGHT)
xDest = -this._global.screen_width;
xDest = this._global.screen_width;
else if (direction == Meta.MotionDirection.RIGHT ||
direction == Meta.MotionDirection.UP_RIGHT ||
direction == Meta.MotionDirection.DOWN_RIGHT)
xDest = -this._global.screen_width;
let switchData = {};
this._switchData = switchData;
switchData.inGroup = new Clutter.Group();
switchData.outGroup = new Clutter.Group();
switchData.windows = [];
let switchData = {};
this._switchData = switchData;
switchData.inGroup = new Clutter.Group();
switchData.outGroup = new Clutter.Group();
switchData.windows = [];
let wgroup = this._global.window_group;
wgroup.add_actor(switchData.inGroup);
wgroup.add_actor(switchData.outGroup);
let wgroup = this._global.window_group;
wgroup.add_actor(switchData.inGroup);
wgroup.add_actor(switchData.outGroup);
for (let i = 0; i < windows.length; i++) {
let window = windows[i];
if (window.get_workspace() == from) {
switchData.windows.push({ window: window,
parent: window.get_parent() });
window.reparent(switchData.outGroup);
} else if (window.get_workspace() == to) {
switchData.windows.push({ window: window,
parent: window.get_parent() });
window.reparent(switchData.inGroup);
window.show_all();
for (let i = 0; i < windows.length; i++) {
let window = windows[i];
if (window.get_workspace() == from) {
switchData.windows.push({ window: window,
parent: window.get_parent() });
window.reparent(switchData.outGroup);
} else if (window.get_workspace() == to) {
switchData.windows.push({ window: window,
parent: window.get_parent() });
window.reparent(switchData.inGroup);
window.show_all();
}
}
switchData.inGroup.set_position(-xDest, -yDest);
switchData.inGroup.raise_top();
Tweener.addTween(switchData.outGroup,
{ x: xDest,
y: yDest,
time: SWITCH_ANIMATION_TIME,
transition: "easeOutBack",
onComplete: this.switchWorkspaceDone
});
Tweener.addTween(switchData.inGroup,
{ x: 0,
y: 0,
time: SWITCH_ANIMATION_TIME,
transition: "easeOutBack"
});
},
switchWorkspaceDone : function() {
let switchData = this._switchData;
if (!switchData)
return;
this._switchData = null;
for (let i = 0; i < switchData.windows.length; i++) {
let w = switchData.windows[i];
if (w.window.get_parent() == switchData.outGroup) {
w.window.reparent(w.parent);
w.window.hide();
} else
w.window.reparent(w.parent);
}
Tweener.removeTweens(switchData.inGroup);
Tweener.removeTweens(switchData.outGroup);
switchData.inGroup.destroy();
switchData.outGroup.destroy();
this._shellwm.completed_switch_workspace();
}
switchData.inGroup.set_position(-xDest, -yDest);
switchData.inGroup.raise_top();
Tweener.addTween(switchData.outGroup,
{ x: xDest,
y: yDest,
time: SWITCH_ANIMATION_TIME,
transition: "easeOutBack",
onComplete: this.switchWorkspaceDone
});
Tweener.addTween(switchData.inGroup,
{ x: 0,
y: 0,
time: SWITCH_ANIMATION_TIME,
transition: "easeOutBack"
});
},
switchWorkspaceDone : function() {
let switchData = this._switchData;
if (!switchData)
return;
this._switchData = null;
for (let i = 0; i < switchData.windows.length; i++) {
let w = switchData.windows[i];
if (w.window.get_parent() == switchData.outGroup) {
w.window.reparent(w.parent);
w.window.hide();
} else
w.window.reparent(w.parent);
}
Tweener.removeTweens(switchData.inGroup);
Tweener.removeTweens(switchData.outGroup);
switchData.inGroup.destroy();
switchData.outGroup.destroy();
this._shellwm.completed_switch_workspace();
}
};