gnome-shell/js/ui/altTab.js
Steve Frécinaux fee385ba35 [AppSwitcher] Do not show the glow for icons in alt+tab dialog.
Unlike icons in the application well, do not show the glow used to
indicate running apps.  It is somewhat redundant here.  These are all
running apps and it is fairly clear from the window list if there are
multiple instances available, according to mccann.

https://bugzilla.gnome.org/show_bug.cgi?id=590563
2009-09-29 18:43:35 +02:00

288 lines
9.7 KiB
JavaScript

/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Big = imports.gi.Big;
const Clutter = imports.gi.Clutter;
const Gdk = imports.gi.Gdk;
const Lang = imports.lang;
const Meta = imports.gi.Meta;
const Pango = imports.gi.Pango;
const Shell = imports.gi.Shell;
const AppIcon = imports.ui.appIcon;
const Lightbox = imports.ui.lightbox;
const Main = imports.ui.main;
const POPUP_BG_COLOR = new Clutter.Color();
POPUP_BG_COLOR.from_pixel(0x00000080);
const POPUP_APPICON_BORDER_COLOR = new Clutter.Color();
POPUP_APPICON_BORDER_COLOR.from_pixel(0xffffffff);
const POPUP_GRID_SPACING = 8;
const POPUP_ICON_SIZE = 48;
const POPUP_NUM_COLUMNS = 5;
const POPUP_POINTER_SELECTION_THRESHOLD = 3;
function AltTabPopup() {
this._init();
}
AltTabPopup.prototype = {
_init : function() {
this.actor = new Big.Box({ background_color : POPUP_BG_COLOR,
corner_radius: POPUP_GRID_SPACING,
padding: POPUP_GRID_SPACING,
spacing: POPUP_GRID_SPACING,
orientation: Big.BoxOrientation.VERTICAL,
reactive: true });
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
// Icon grid. TODO: Investigate Nbtk.Grid once that lands. Currently
// just implemented using a chain of Big.Box.
this._grid = new Big.Box({ spacing: POPUP_GRID_SPACING,
orientation: Big.BoxOrientation.VERTICAL });
let gcenterbox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
x_align: Big.BoxAlignment.CENTER });
gcenterbox.append(this._grid, Big.BoxPackFlags.NONE);
this.actor.append(gcenterbox, Big.BoxPackFlags.NONE);
this._icons = [];
this._currentWindows = [];
this._haveModal = false;
this._selected = 0;
this._highlightedWindow = null;
this._toplevels = global.window_group.get_children();
global.stage.add_actor(this.actor);
},
_addIcon : function(appIcon) {
appIcon.connect('activate', Lang.bind(this, this._appClicked));
appIcon.connect('activate-window', Lang.bind(this, this._windowClicked));
appIcon.connect('highlight-window', Lang.bind(this, this._windowHovered));
appIcon.connect('menu-popped-up', Lang.bind(this, this._menuPoppedUp));
appIcon.connect('menu-popped-down', Lang.bind(this, this._menuPoppedDown));
appIcon.actor.connect('enter-event', Lang.bind(this, this._iconEntered));
// FIXME?
appIcon.actor.border = 2;
appIcon.highlight_border_color = POPUP_APPICON_BORDER_COLOR;
this._icons.push(appIcon);
this._currentWindows.push(appIcon.windows[0]);
// Add it to the grid
if (!this._gridRow || this._gridRow.get_children().length == POPUP_NUM_COLUMNS) {
this._gridRow = new Big.Box({ spacing: POPUP_GRID_SPACING,
orientation: Big.BoxOrientation.HORIZONTAL });
this._grid.append(this._gridRow, Big.BoxPackFlags.NONE);
}
this._gridRow.append(appIcon.actor, Big.BoxPackFlags.NONE);
},
show : function(initialSelection) {
let appMonitor = Shell.AppMonitor.get_default();
let apps = appMonitor.get_running_apps ("");
if (!apps.length)
return false;
if (!Main.pushModal(this.actor))
return false;
this._haveModal = true;
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._motionEventId = this.actor.connect('motion-event', Lang.bind(this, this._mouseMoved));
this._mouseActive = false;
this._mouseMovement = 0;
// Contruct the AppIcons, sort by time, add to the popup
let icons = [];
for (let i = 0; i < apps.length; i++)
icons.push(new AppIcon.AppIcon(apps[i], AppIcon.MenuType.BELOW, false));
icons.sort(Lang.bind(this, this._sortAppIcon));
for (let i = 0; i < icons.length; i++)
this._addIcon(icons[i]);
// Need to specify explicit width and height because the
// window_group may not actually cover the whole screen
this._lightbox = new Lightbox.Lightbox(global.window_group,
global.screen_width,
global.screen_height);
this.actor.show_all();
this.actor.x = Math.floor((global.screen_width - this.actor.width) / 2);
this.actor.y = Math.floor((global.screen_height - this.actor.height) / 2);
this._updateSelection(initialSelection);
// There's a race condition; if the user released Alt before
// we got the grab, then we won't be notified. (See
// https://bugzilla.gnome.org/show_bug.cgi?id=596695 for
// details.) So we check now. (Have to do this after calling
// _updateSelection.)
let [screen, x, y, mods] = Gdk.Display.get_default().get_pointer();
if (!(mods & Gdk.ModifierType.MOD1_MASK)) {
this._finish();
return false;
}
return true;
},
_hasVisibleWindows : function(appIcon) {
for (let i = 0; i < appIcon.windows.length; i++) {
if (appIcon.windows[i].showing_on_its_workspace())
return true;
}
return false;
},
_sortAppIcon : function(appIcon1, appIcon2) {
let vis1 = this._hasVisibleWindows(appIcon1);
let vis2 = this._hasVisibleWindows(appIcon2);
if (vis1 && !vis2) {
return -1;
} else if (vis2 && !vis1) {
return 1;
} else {
// The app's most-recently-used window is first
// in its list
return (appIcon2.windows[0].get_user_time() -
appIcon1.windows[0].get_user_time());
}
},
_keyPressEvent : function(actor, event) {
let keysym = event.get_key_symbol();
let backwards = (event.get_state() & Clutter.ModifierType.SHIFT_MASK);
if (keysym == Clutter.Tab)
this._updateSelection(backwards ? -1 : 1);
else if (keysym == Clutter.grave)
this._updateWindowSelection(backwards ? -1 : 1);
else if (keysym == Clutter.Escape)
this.destroy();
return true;
},
_keyReleaseEvent : function(actor, event) {
let keysym = event.get_key_symbol();
if (keysym == Clutter.Alt_L || keysym == Clutter.Alt_R)
this._finish();
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);
},
_mouseMoved : function(actor, event) {
if (++this._mouseMovement < POPUP_POINTER_SELECTION_THRESHOLD)
return;
this.actor.disconnect(this._motionEventId);
this._mouseActive = true;
actor = event.get_source();
while (actor) {
if (actor._delegate instanceof AppIcon.AppIcon) {
this._iconEntered(actor, event);
return;
}
actor = actor.get_parent();
}
},
_iconEntered : function(actor, event) {
let index = this._icons.indexOf(actor._delegate);
if (this._mouseActive)
this._updateSelection(index - this._selected);
},
_finish : function() {
if (this._highlightedWindow)
Main.activateWindow(this._highlightedWindow);
this.destroy();
},
destroy : function() {
this.actor.destroy();
},
_onDestroy : function() {
if (this._haveModal)
Main.popModal(this.actor);
if (this._lightbox)
this._lightbox.destroy();
if (this._keyPressEventId)
global.stage.disconnect(this._keyPressEventId);
if (this._keyReleaseEventId)
global.stage.disconnect(this._keyReleaseEventId);
},
_updateSelection : function(delta) {
this._icons[this._selected].setHighlight(false);
if (delta != 0 && this._selectedMenu)
this._selectedMenu.popdown();
this._selected = (this._selected + this._icons.length + delta) % this._icons.length;
this._icons[this._selected].setHighlight(true);
this._highlightWindow(this._currentWindows[this._selected]);
},
_menuPoppedUp : function(icon, menu) {
this._selectedMenu = menu;
},
_menuPoppedDown : function(icon, menu) {
this._selectedMenu = null;
},
_updateWindowSelection : function(delta) {
let icon = this._icons[this._selected];
if (!this._selectedMenu)
icon.popupMenu();
if (!this._selectedMenu)
return;
let next = 0;
for (let i = 0; i < icon.windows.length; i++) {
if (icon.windows[i] == this._highlightedWindow) {
next = (i + icon.windows.length + delta) % icon.windows.length;
break;
}
}
this._selectedMenu.selectWindow(icon.windows[next]);
},
_highlightWindow : function(metaWin) {
this._highlightedWindow = metaWin;
this._currentWindows[this._selected] = metaWin;
this._lightbox.highlight(this._highlightedWindow.get_compositor_private());
}
};