[AppSwitcher] Use AppIcon and switch applications rather than windows
https://bugzilla.gnome.org/show_bug.cgi?id=590563
This commit is contained in:
parent
11d884d724
commit
67bfbc9b4b
169
js/ui/altTab.js
169
js/ui/altTab.js
@ -7,26 +7,19 @@ const Meta = imports.gi.Meta;
|
|||||||
const Pango = imports.gi.Pango;
|
const Pango = imports.gi.Pango;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
|
|
||||||
|
const AppIcon = imports.ui.appIcon;
|
||||||
const Lightbox = imports.ui.lightbox;
|
const Lightbox = imports.ui.lightbox;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const Tweener = imports.ui.tweener;
|
|
||||||
|
|
||||||
const POPUP_BG_COLOR = new Clutter.Color();
|
const POPUP_BG_COLOR = new Clutter.Color();
|
||||||
POPUP_BG_COLOR.from_pixel(0x00000080);
|
POPUP_BG_COLOR.from_pixel(0x000000ff);
|
||||||
const POPUP_INDICATOR_COLOR = new Clutter.Color();
|
|
||||||
POPUP_INDICATOR_COLOR.from_pixel(0xf0f0f0ff);
|
|
||||||
const POPUP_TRANSPARENT = new Clutter.Color();
|
const POPUP_TRANSPARENT = new Clutter.Color();
|
||||||
POPUP_TRANSPARENT.from_pixel(0x00000000);
|
POPUP_TRANSPARENT.from_pixel(0x00000000);
|
||||||
|
|
||||||
const POPUP_INDICATOR_WIDTH = 4;
|
|
||||||
const POPUP_GRID_SPACING = 8;
|
const POPUP_GRID_SPACING = 8;
|
||||||
const POPUP_ICON_SIZE = 48;
|
const POPUP_ICON_SIZE = 48;
|
||||||
const POPUP_NUM_COLUMNS = 5;
|
const POPUP_NUM_COLUMNS = 5;
|
||||||
|
|
||||||
const POPUP_LABEL_MAX_WIDTH = POPUP_NUM_COLUMNS * (POPUP_ICON_SIZE + POPUP_GRID_SPACING);
|
|
||||||
|
|
||||||
const SWITCH_TIME = 0.1;
|
|
||||||
|
|
||||||
function AltTabPopup() {
|
function AltTabPopup() {
|
||||||
this._init();
|
this._init();
|
||||||
}
|
}
|
||||||
@ -50,48 +43,24 @@ AltTabPopup.prototype = {
|
|||||||
gcenterbox.append(this._grid, Big.BoxPackFlags.NONE);
|
gcenterbox.append(this._grid, Big.BoxPackFlags.NONE);
|
||||||
this.actor.append(gcenterbox, Big.BoxPackFlags.NONE);
|
this.actor.append(gcenterbox, Big.BoxPackFlags.NONE);
|
||||||
|
|
||||||
// Selected-window label
|
this._icons = [];
|
||||||
this._label = new Clutter.Text({ font_name: "Sans 16px",
|
|
||||||
ellipsize: Pango.EllipsizeMode.END });
|
|
||||||
|
|
||||||
let labelbox = new Big.Box({ background_color: POPUP_INDICATOR_COLOR,
|
|
||||||
corner_radius: POPUP_GRID_SPACING / 2,
|
|
||||||
padding: POPUP_GRID_SPACING / 2 });
|
|
||||||
labelbox.append(this._label, Big.BoxPackFlags.NONE);
|
|
||||||
let lcenterbox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
|
||||||
x_align: Big.BoxAlignment.CENTER,
|
|
||||||
width: POPUP_LABEL_MAX_WIDTH + POPUP_GRID_SPACING });
|
|
||||||
lcenterbox.append(labelbox, Big.BoxPackFlags.NONE);
|
|
||||||
this.actor.append(lcenterbox, Big.BoxPackFlags.NONE);
|
|
||||||
|
|
||||||
// Indicator around selected icon
|
|
||||||
this._indicator = new Big.Rectangle({ border_width: POPUP_INDICATOR_WIDTH,
|
|
||||||
corner_radius: POPUP_INDICATOR_WIDTH / 2,
|
|
||||||
border_color: POPUP_INDICATOR_COLOR,
|
|
||||||
color: POPUP_TRANSPARENT });
|
|
||||||
this.actor.append(this._indicator, Big.BoxPackFlags.FIXED);
|
|
||||||
|
|
||||||
this._items = [];
|
|
||||||
this._haveModal = false;
|
this._haveModal = false;
|
||||||
|
this._selected = 0;
|
||||||
|
this._highlightedWindow = null;
|
||||||
|
this._toplevels = global.window_group.get_children();
|
||||||
|
|
||||||
global.stage.add_actor(this.actor);
|
global.stage.add_actor(this.actor);
|
||||||
},
|
},
|
||||||
|
|
||||||
_addWindow : function(win) {
|
_addIcon : function(appIcon) {
|
||||||
let item = { window: win,
|
appIcon.connect('activate', Lang.bind(this, this._appClicked));
|
||||||
metaWindow: win.get_meta_window() };
|
appIcon.connect('activate-window', Lang.bind(this, this._windowClicked));
|
||||||
|
appIcon.connect('highlight-window', Lang.bind(this, this._windowHovered));
|
||||||
|
|
||||||
let pixbuf = item.metaWindow.icon;
|
// FIXME?
|
||||||
item.icon = new Clutter.Texture({ width: POPUP_ICON_SIZE,
|
appIcon.actor.border = 2;
|
||||||
height: POPUP_ICON_SIZE,
|
|
||||||
keep_aspect_ratio: true });
|
|
||||||
Shell.clutter_texture_set_from_pixbuf(item.icon, pixbuf);
|
|
||||||
|
|
||||||
item.box = new Big.Box({ padding: POPUP_INDICATOR_WIDTH * 2 });
|
this._icons.push(appIcon);
|
||||||
item.box.append(item.icon, Big.BoxPackFlags.NONE);
|
|
||||||
|
|
||||||
item.n = this._items.length;
|
|
||||||
this._items.push(item);
|
|
||||||
|
|
||||||
// Add it to the grid
|
// Add it to the grid
|
||||||
if (!this._gridRow || this._gridRow.get_children().length == POPUP_NUM_COLUMNS) {
|
if (!this._gridRow || this._gridRow.get_children().length == POPUP_NUM_COLUMNS) {
|
||||||
@ -99,7 +68,7 @@ AltTabPopup.prototype = {
|
|||||||
orientation: Big.BoxOrientation.HORIZONTAL });
|
orientation: Big.BoxOrientation.HORIZONTAL });
|
||||||
this._grid.append(this._gridRow, Big.BoxPackFlags.NONE);
|
this._grid.append(this._gridRow, Big.BoxPackFlags.NONE);
|
||||||
}
|
}
|
||||||
this._gridRow.append(item.box, Big.BoxPackFlags.NONE);
|
this._gridRow.append(appIcon.actor, Big.BoxPackFlags.NONE);
|
||||||
},
|
},
|
||||||
|
|
||||||
show : function(initialSelection) {
|
show : function(initialSelection) {
|
||||||
@ -116,17 +85,18 @@ AltTabPopup.prototype = {
|
|||||||
this._keyPressEventId = global.stage.connect('key-press-event', Lang.bind(this, this._keyPressEvent));
|
this._keyPressEventId = global.stage.connect('key-press-event', Lang.bind(this, this._keyPressEvent));
|
||||||
this._keyReleaseEventId = global.stage.connect('key-release-event', Lang.bind(this, this._keyReleaseEvent));
|
this._keyReleaseEventId = global.stage.connect('key-release-event', Lang.bind(this, this._keyReleaseEvent));
|
||||||
|
|
||||||
// Fill in the windows
|
// Contruct the AppIcons, sort by time, add to the popup
|
||||||
let windows = [];
|
let icons = [];
|
||||||
for (let i = 0; i < apps.length; i++) {
|
for (let i = 0; i < apps.length; i++)
|
||||||
let appWindows = appMonitor.get_windows_for_app(apps[i].get_id());
|
icons.push(new AppIcon.AppIcon(apps[i], AppIcon.MenuType.BELOW));
|
||||||
windows = windows.concat(appWindows);
|
icons.sort(function(i1, i2) {
|
||||||
}
|
// The app's most-recently-used window is first
|
||||||
|
// in its list
|
||||||
windows.sort(function(w1, w2) { return w2.get_user_time() - w1.get_user_time(); });
|
return (i2.windows[0].get_user_time() -
|
||||||
|
i1.windows[0].get_user_time());
|
||||||
for (let i = 0; i < windows.length; i++)
|
});
|
||||||
this._addWindow(windows[i].get_compositor_private());
|
for (let i = 0; i < icons.length; i++)
|
||||||
|
this._addIcon(icons[i]);
|
||||||
|
|
||||||
// Need to specify explicit width and height because the
|
// Need to specify explicit width and height because the
|
||||||
// window_group may not actually cover the whole screen
|
// window_group may not actually cover the whole screen
|
||||||
@ -158,16 +128,30 @@ AltTabPopup.prototype = {
|
|||||||
let keysym = event.get_key_symbol();
|
let keysym = event.get_key_symbol();
|
||||||
|
|
||||||
if (keysym == Clutter.Alt_L || keysym == Clutter.Alt_R) {
|
if (keysym == Clutter.Alt_L || keysym == Clutter.Alt_R) {
|
||||||
if (this._selected) {
|
if (this._highlightedWindow)
|
||||||
Main.activateWindow(this._selected.metaWindow,
|
Main.activateWindow(this._highlightedWindow, event.get_time());
|
||||||
event.get_time());
|
|
||||||
}
|
|
||||||
this.destroy();
|
this.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_appClicked : function(icon) {
|
||||||
|
Main.activateWindow(icon.windows[0]);
|
||||||
|
this.destroy();
|
||||||
|
},
|
||||||
|
|
||||||
|
_windowClicked : function(icon, window) {
|
||||||
|
if (window)
|
||||||
|
Main.activateWindow(window);
|
||||||
|
this.destroy();
|
||||||
|
},
|
||||||
|
|
||||||
|
_windowHovered : function(icon, window) {
|
||||||
|
if (window)
|
||||||
|
this._highlightWindow(window);
|
||||||
|
},
|
||||||
|
|
||||||
destroy : function() {
|
destroy : function() {
|
||||||
this.actor.destroy();
|
this.actor.destroy();
|
||||||
},
|
},
|
||||||
@ -186,66 +170,15 @@ AltTabPopup.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
_updateSelection : function(delta) {
|
_updateSelection : function(delta) {
|
||||||
let n = ((this._selected ? this._selected.n : 0) + this._items.length + delta) % this._items.length;
|
this._icons[this._selected].setHighlight(false);
|
||||||
|
this._selected = (this._selected + this._icons.length + delta) % this._icons.length;
|
||||||
|
this._icons[this._selected].setHighlight(true);
|
||||||
|
|
||||||
if (this._selected) {
|
this._highlightWindow(this._icons[this._selected].windows[0]);
|
||||||
// Unselect previous
|
|
||||||
|
|
||||||
if (this._allocationChangedId) {
|
|
||||||
this._selected.box.disconnect(this._allocationChangedId);
|
|
||||||
delete this._allocationChangedId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let item = this._items[n];
|
|
||||||
let changed = this._selected && item != this._selected;
|
|
||||||
this._selected = item;
|
|
||||||
|
|
||||||
if (this._selected) {
|
|
||||||
this._label.set_size(-1, -1);
|
|
||||||
this._label.text = this._selected.metaWindow.title;
|
|
||||||
if (this._label.width > POPUP_LABEL_MAX_WIDTH)
|
|
||||||
this._label.width = POPUP_LABEL_MAX_WIDTH;
|
|
||||||
|
|
||||||
// Figure out this._selected.box's coordinates in terms of
|
|
||||||
// this.actor
|
|
||||||
let bx = this._selected.box.x, by = this._selected.box.y;
|
|
||||||
let actor = this._selected.box.get_parent();
|
|
||||||
while (actor != this.actor) {
|
|
||||||
bx += actor.x;
|
|
||||||
by += actor.y;
|
|
||||||
actor = actor.get_parent();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (changed) {
|
|
||||||
Tweener.addTween(this._indicator,
|
|
||||||
{ x: bx,
|
|
||||||
y: by,
|
|
||||||
width: this._selected.box.width,
|
|
||||||
height: this._selected.box.height,
|
|
||||||
time: SWITCH_TIME,
|
|
||||||
transition: "easeOutQuad" });
|
|
||||||
} else {
|
|
||||||
Tweener.removeTweens(this.indicator);
|
|
||||||
this._indicator.set_position(bx, by);
|
|
||||||
this._indicator.set_size(this._selected.box.width,
|
|
||||||
this._selected.box.height);
|
|
||||||
}
|
|
||||||
this._indicator.show();
|
|
||||||
|
|
||||||
this._lightbox.highlight(this._selected.window);
|
|
||||||
|
|
||||||
this._allocationChangedId =
|
|
||||||
this._selected.box.connect('notify::allocation',
|
|
||||||
Lang.bind(this, this._allocationChanged));
|
|
||||||
} else {
|
|
||||||
this._label.text = "";
|
|
||||||
this._indicator.hide();
|
|
||||||
this._lightbox.highlight(null);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_allocationChanged : function() {
|
_highlightWindow : function(metaWin) {
|
||||||
this._updateSelection(0);
|
this._highlightedWindow = metaWin;
|
||||||
|
this._lightbox.highlight(this._highlightedWindow.get_compositor_private());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user