Files
gnome-shell-extensions/extensions/dock/extension.js
2012-04-29 22:35:24 +02:00

969 lines
33 KiB
JavaScript

/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Pango = imports.gi.Pango;
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Gtk = imports.gi.Gtk;
const Shell = imports.gi.Shell;
const Lang = imports.lang;
const Signals = imports.signals;
const St = imports.gi.St;
const Mainloop = imports.mainloop;
const AppFavorites = imports.ui.appFavorites;
const DND = imports.ui.dnd;
const Main = imports.ui.main;
const Overview = imports.ui.overview;
const PopupMenu = imports.ui.popupMenu;
const Search = imports.ui.search;
const Tweener = imports.ui.tweener;
const Workspace = imports.ui.workspace;
const AppDisplay = imports.ui.appDisplay;
const AltTab = imports.ui.altTab;
const Gettext = imports.gettext.domain('gnome-shell-extensions');
const _ = Gettext.gettext;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const Convenience = Me.imports.convenience;
// Settings
const DOCK_POSITION_KEY = 'position';
const DOCK_SIZE_KEY = 'size';
const DOCK_HIDE_KEY = 'autohide';
const DOCK_EFFECTHIDE_KEY = 'hide-effect';
const DOCK_AUTOHIDE_ANIMATION_TIME_KEY = 'hide-effect-duration';
const DOCK_MONITOR_KEY = 'monitor';
// Keep enums in sync with GSettings schemas
const PositionMode = {
LEFT: 0,
RIGHT: 1
};
const AutoHideEffect = {
RESIZE: 0,
RESCALE: 1,
MOVE: 2
};
const DND_RAISE_APP_TIMEOUT = 500;
// Utility function to make the dock clipped to the primary monitor
function updateClip(actor, monitorNumber) {
let monitor;
if (monitorNumber > -1 && monitorNumber < Main.layoutManager.monitors.length)
monitor = Main.layoutManager.monitors[monitorNumber];
else
monitor = Main.layoutManager.primaryMonitor;
let allocation = actor.allocation;
// Here we implicitly assume that the stage and actor's parent
// share the same coordinate space
let clip = new Clutter.ActorBox({ x1: Math.max(monitor.x, allocation.x1),
y1: Math.max(monitor.y, allocation.y1),
x2: Math.min(monitor.x + monitor.width, allocation.x2),
y2: Math.min(monitor.y + monitor.height, allocation.y2) });
// Translate back into actor's coordinate space
clip.x1 -= actor.x;
clip.x2 -= actor.x;
clip.y1 -= actor.y;
clip.y2 -= actor.y;
// Apply the clip
actor.set_clip(clip.x1, clip.y1, clip.x2-clip.x1, clip.y2 - clip.y1);
}
/*************************************************************************************/
/**** start resize's Dock functions *****************/
/*************************************************************************************/
function hideDock_size () {
if (!this._hideable)
return;
let monitor = Main.layoutManager.primaryMonitor;
if (this._displayMonitor > -1 && this._displayMonitor < Main.layoutManager.monitors.length) {
monitor = Main.layoutManager.monitors[this._displayMonitor];
}
let position_x = monitor.x;
let height = (this._nicons)*(this._item_size + this._spacing) + 2*this._spacing;
let width = this._item_size + 4*this._spacing;
Tweener.addTween(this, {
_item_size: 1,
time: this._settings.get_double(DOCK_AUTOHIDE_ANIMATION_TIME_KEY),
transition: 'easeOutQuad',
onUpdate: function () {
height = (this._nicons)*(this._item_size + this._spacing) + 2*this._spacing;
width = this._item_size + 4*this._spacing;
switch (this._settings.get_enum(DOCK_POSITION_KEY)) {
case PositionMode.LEFT:
position_x=monitor.x-2*this._spacing;
break;
case PositionMode.RIGHT:
default:
position_x = monitor.x + (monitor.width-1-this._item_size-2*this._spacing);
}
this.actor.set_position (position_x,monitor.y+(monitor.height-height)/2);
this.actor.set_size(width,height);
updateClip(this.actor, this._displayMonitor);
},
});
this._hidden = true;
}
function showDock_size () {
let monitor = Main.layoutManager.primaryMonitor;
if (this._displayMonitor > -1 && this._displayMonitor < Main.layoutManager.monitors.length) {
monitor = Main.layoutManager.monitors[this._displayMonitor];
}
let height = (this._nicons)*(this._item_size + this._spacing) + 2*this._spacing;
let width = this._item_size + 4*this._spacing;
let position_x = monitor.x;
Tweener.addTween(this, {
_item_size: this._settings.get_int(DOCK_SIZE_KEY),
time: this._settings.get_double(DOCK_AUTOHIDE_ANIMATION_TIME_KEY),
transition: 'easeOutQuad',
onUpdate: function () {
height = (this._nicons)*(this._item_size + this._spacing) + 2*this._spacing;
width = this._item_size + 4*this._spacing;
switch (this._settings.get_enum(DOCK_POSITION_KEY)) {
case PositionMode.LEFT:
position_x=monitor.x-2*this._spacing;
break;
case PositionMode.RIGHT:
default:
position_x=monitor.x + (monitor.width-this._item_size-2*this._spacing);
}
this.actor.set_position (position_x, monitor.y+(monitor.height-height)/2);
this.actor.set_size(width,height);
updateClip(this.actor, this._displayMonitor);
}
});
this._hidden = false;
}
function showEffectAddItem_size () {
let primary = Main.layoutManager.primaryMonitor;
let height = (this._nicons)*(this._item_size + this._spacing) + 2*this._spacing;
let width = this._item_size + 4*this._spacing;
Tweener.addTween(this.actor, {
y: primary.y + (primary.height-height)/2,
height: height,
width: width,
time: this._settings.get_double(DOCK_AUTOHIDE_ANIMATION_TIME_KEY),
transition: 'easeOutQuad',
onUpdate: function (monitor) {
updateClip(this, monitor);
},
onUpdateParams: [this._displayMonitor]
});
}
/**************************************************************************************/
/**** start rescale's Dock functions *****************/
/**************************************************************************************/
function hideDock_scale () {
if (!this._hideable)
return;
this._item_size = this._settings.get_int(DOCK_SIZE_KEY);
let monitor = Main.layoutManager.primaryMonitor;
if (this._displayMonitor > -1 && this._displayMonitor < Main.layoutManager.monitors.length) {
monitor = Main.layoutManager.monitors[this._displayMonitor];
}
let cornerX = 0;
let height = this._nicons*(this._item_size + this._spacing) + 2*this._spacing;
let width = this._item_size + 4*this._spacing;
switch (this._settings.get_enum(DOCK_POSITION_KEY)) {
case PositionMode.LEFT:
cornerX=monitor.x;
break;
case PositionMode.RIGHT:
default:
cornerX = monitor.x + monitor.width-1;
}
Tweener.addTween(this.actor,{
y: monitor.y + (monitor.height-height)/2,
x: cornerX,
height:height,
width: width,
scale_x: 0.025,
time: this._settings.get_double(DOCK_AUTOHIDE_ANIMATION_TIME_KEY),
transition: 'easeOutQuad',
onUpdate: function(monitor) {
updateClip(this, monitor);
},
onUpdateParams: [this._displayMonitor]
});
this._hidden = true;
}
function showDock_scale () {
this._item_size = this._settings.get_int(DOCK_SIZE_KEY);
let monitor = Main.layoutManager.primaryMonitor;
if (this._displayMonitor > -1 && this._displayMonitor < Main.layoutManager.monitors.length) {
monitor = Main.layoutManager.monitors[this._displayMonitor];
}
let position_x = monitor.x;
let height = this._nicons*(this._item_size + this._spacing) + 2*this._spacing;
let width = this._item_size + 4*this._spacing;
switch (this._settings.get_enum(DOCK_POSITION_KEY)) {
case PositionMode.LEFT:
position_x=monitor.x-2*this._spacing;
break;
case PositionMode.RIGHT:
default:
position_x=monitor.x + (monitor.width-this._item_size-2*this._spacing);
}
Tweener.addTween(this.actor, {
y: monitor.y + (monitor.height-height)/2,
x: monitor.x + position_x,
height: height,
width: width,
scale_x: 1,
time: this._settings.get_double(DOCK_AUTOHIDE_ANIMATION_TIME_KEY),
transition: 'easeOutQuad',
onUpdate: function(monitor) {
updateClip(this, monitor);
},
onUpdateParams: [this._displayMonitor]
});
this._hidden = false;
}
function showEffectAddItem_scale () {
let monitor = Main.layoutManager.primaryMonitor;
if (this._displayMonitor > -1 && this._displayMonitor < Main.layoutManager.monitors.length) {
monitor = Main.layoutManager.monitors[this._displayMonitor];
}
let height = this._nicons*(this._item_size + this._spacing) + 2*this._spacing;
let width = this._item_size + 4*this._spacing;
Tweener.addTween(this.actor, {
y: monitor.y + (monitor.height-height)/2,
height: height,
width: width,
time: this._settings.get_double(DOCK_AUTOHIDE_ANIMATION_TIME_KEY),
transition: 'easeOutQuad',
onUpdate: function(monitor) {
updateClip(this, monitor);
},
onUpdateParams: [this._displayMonitor]
});
}
/**************************************************************************************/
/**** start move Dock functions *****************/
/**************************************************************************************/
function hideDock_move () {
if (!this._hideable)
return;
this._item_size = this._settings.get_int(DOCK_SIZE_KEY);
let monitor = Main.layoutManager.primaryMonitor;
if (this._displayMonitor > -1 && this._displayMonitor < Main.layoutManager.monitors.length) {
monitor = Main.layoutManager.monitors[this._displayMonitor];
}
let cornerX = 0;
let height = this._nicons*(this._item_size + this._spacing) + 2*this._spacing;
let width = this._item_size + 4*this._spacing;
switch (this._settings.get_enum(DOCK_POSITION_KEY)) {
case PositionMode.LEFT:
cornerX= monitor.x - width + this._spacing;
break;
case PositionMode.RIGHT:
default:
cornerX = monitor.x + monitor.width - this._spacing;
}
Tweener.addTween(this.actor,{
x: cornerX,
y: monitor.y + (monitor.height - height)/2,
width: width,
height: height,
time: this._settings.get_double(DOCK_AUTOHIDE_ANIMATION_TIME_KEY),
transition: 'easeOutQuad',
onUpdate: function(monitor) {
updateClip(this, monitor);
},
onUpdateParams: [this._displayMonitor]
});
this._hidden = true;
}
function showDock_move () {
this._item_size = this._settings.get_int(DOCK_SIZE_KEY);
let monitor = Main.layoutManager.primaryMonitor;
if (this._displayMonitor > -1 && this._displayMonitor < Main.layoutManager.monitors.length) {
monitor = Main.layoutManager.monitors[this._displayMonitor];
}
let position_x = monitor.x;
let height = this._nicons*(this._item_size + this._spacing) + 2*this._spacing;
let width = this._item_size + 4*this._spacing;
switch (this._settings.get_enum(DOCK_POSITION_KEY)) {
case PositionMode.LEFT:
position_x=monitor.x - 2*this._spacing;
break;
case PositionMode.RIGHT:
default:
position_x=monitor.x + (monitor.width-this._item_size-2*this._spacing);
}
Tweener.addTween(this.actor, {
x: position_x,
y: monitor.y + (monitor.height - height)/2,
width: width,
height: height,
time: this._settings.get_double(DOCK_AUTOHIDE_ANIMATION_TIME_KEY),
transition: 'easeOutQuad',
onUpdate: function(monitor) {
updateClip(this, monitor);
},
onUpdateParams: [this._displayMonitor]
});
this._hidden = false;
}
function showEffectAddItem_move () {
let monitor = Main.layoutManager.primaryMonitor;
if (this._displayMonitor > -1 && this._displayMonitor < Main.layoutManager.monitors.length) {
monitor = Main.layoutManager.monitors[this._displayMonitor];
}
let height = this._nicons*(this._item_size + this._spacing) + 2*this._spacing;
let width = this._item_size + 4*this._spacing;
Tweener.addTween(this.actor, {
y: monitor.y + (monitor.height-height)/2,
height: height,
width: width,
time: this._settings.get_double(DOCK_AUTOHIDE_ANIMATION_TIME_KEY),
transition: 'easeOutQuad',
onUpdate: function(monitor) {
updateClip(this, monitor);
},
onUpdateParams: [this._displayMonitor]
});
}
const Dock = new Lang.Class({
Name: 'Dock.Dock',
_init : function() {
this._placeholderText = null;
this._menus = [];
this._menuDisplays = [];
this._favorites = [];
// Load Settings
this._settings = Convenience.getSettings();
this._hidden = false;
this._hideable = this._settings.get_boolean(DOCK_HIDE_KEY);
this._displayMonitor = this._settings.get_int(DOCK_MONITOR_KEY);
this._spacing = 4;
this._item_size = this._settings.get_int(DOCK_SIZE_KEY);
this._nicons = 0;
this._selectEffectFunctions(this._settings.get_enum(DOCK_EFFECTHIDE_KEY));
this.actor = new St.BoxLayout({ name: 'dock', vertical: true, reactive: true });
this._grid = new Shell.GenericContainer();
this.actor.add(this._grid, { expand: true, y_align: St.Align.START });
this.actor.connect('style-changed', Lang.bind(this, this._onStyleChanged));
this._grid.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
this._grid.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
this._grid.connect('allocate', Lang.bind(this, this._allocate));
this._workId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._redisplay));
this._tracker = Shell.WindowTracker.get_default();
this._appSystem = Shell.AppSystem.get_default();
this._installedChangedId = this._appSystem.connect('installed-changed', Lang.bind(this, this._queueRedisplay));
this._appFavoritesChangedId = AppFavorites.getAppFavorites().connect('changed', Lang.bind(this, this._queueRedisplay));
this._appStateChangedId = this._appSystem.connect('app-state-changed', Lang.bind(this, this._queueRedisplay));
this._overviewShowingId = Main.overview.connect('showing', Lang.bind(this, function() {
this.actor.hide();
}));
this._overviewHiddenId = Main.overview.connect('hidden', Lang.bind(this, function() {
this.actor.show();
}));
Main.layoutManager.addChrome(this.actor,
{ affectsStruts: !this._settings.get_boolean(DOCK_HIDE_KEY) });
//hidden
this._settings.connect('changed::'+DOCK_POSITION_KEY, Lang.bind(this, this._redisplay));
this._settings.connect('changed::'+DOCK_SIZE_KEY, Lang.bind(this, this._redisplay));
this._settings.connect('changed::'+DOCK_MONITOR_KEY, Lang.bind(this, function (){
this._displayMonitor = this._settings.get_int(DOCK_MONITOR_KEY);
this._redisplay();
}));
this._settings.connect('changed::'+DOCK_HIDE_KEY, Lang.bind(this, function (){
Main.layoutManager.removeChrome(this.actor);
Main.layoutManager.addChrome(this.actor,
{ affectsStruts: !this._settings.get_boolean(DOCK_HIDE_KEY) });
this._hideable = this._settings.get_boolean(DOCK_HIDE_KEY);
if (this._hideable)
this._hideDock();
else
this._showDock();
}));
this._settings.connect('changed::' + DOCK_EFFECTHIDE_KEY, Lang.bind(this, function () {
let hideEffect = this._settings.get_enum(DOCK_EFFECTHIDE_KEY);
// restore the effects of the other functions
switch (hideEffect) {
case AutoHideEffect.RESCALE:
this._item_size = this._settings.get_int(DOCK_SIZE_KEY);
break;
case AutoHideEffect.RESIZE:
this.actor.set_scale(1, 1);
break;
case AutoHideEffect.MOVE:
this.actor.set_scale(1, 1);
this._item_size = this._settings.get_int(DOCK_SIZE_KEY);
}
this.actor.disconnect(this._leave_event);
this.actor.disconnect(this._enter_event);
this._selectEffectFunctions(hideEffect);
this._leave_event = this.actor.connect('leave-event', Lang.bind(this, this._hideDock));
this._enter_event = this.actor.connect('enter-event', Lang.bind(this, this._showDock));
this._redisplay();
}));
this._leave_event = this.actor.connect('leave-event', Lang.bind(this, this._hideDock));
this._enter_event = this.actor.connect('enter-event', Lang.bind(this, this._showDock));
this._hideDock();
},
destroy: function() {
if (this._installedChangedId) {
this._appSystem.disconnect(this._installedChangedId);
this._installedChangedId = 0;
}
if (this._appFavoritesChangedId) {
AppFavorites.getAppFavorites().disconnect(this._appFavoritesChangedId);
this._appFavoritesChangedId = 0;
}
if (this._appStateChangedId) {
this._appSystem.disconnect(this._appStateChangedId);
this._appStateChangedId = 0;
}
if (this._overviewShowingId) {
Main.overview.disconnect(this._overviewShowingId);
this._overviewShowingId = 0;
}
if (this._overviewHiddenId) {
Main.overview.disconnect(this._overviewHiddenId);
this._overviewHiddenId = 0;
}
this.actor.destroy();
// Break reference cycles
this._settings.run_dispose();
this._settings = null;
this._appSystem = null;
this._tracker = null;
},
// fuctions hide
_restoreHideDock: function() {
this._hideable = this._settings.get_boolean(DOCK_HIDE_KEY);
},
_disableHideDock: function() {
this._hideable = false;
},
_selectEffectFunctions: function(hideEffect) {
switch (hideEffect) {
case AutoHideEffect.RESCALE:
this._hideDock = hideDock_scale;
this._showDock = showDock_scale;
this._showEffectAddItem = showEffectAddItem_scale;
break;
case AutoHideEffect.MOVE:
this._hideDock = hideDock_move;
this._showDock = showDock_move;
this._showEffectAddItem = showEffectAddItem_move;
break;
case AutoHideEffect.RESIZE:
default:
this._hideDock = hideDock_size;
this._showDock = showDock_size;
this._showEffectAddItem = showEffectAddItem_size;
}
},
_appIdListToHash: function(apps) {
let ids = {};
for (let i = 0; i < apps.length; i++)
ids[apps[i].get_id()] = apps[i];
return ids;
},
_queueRedisplay: function () {
Main.queueDeferredWork(this._workId);
},
_redisplay: function () {
this.removeAll();
let favorites = AppFavorites.getAppFavorites().getFavoriteMap();
let running = this._appSystem.get_running();
let runningIds = this._appIdListToHash(running);
let icons = 0;
let nFavorites = 0;
for (let id in favorites) {
let app = favorites[id];
let display = new DockIcon(app,this);
this.addItem(display.actor);
nFavorites++;
icons++;
}
for (let i = 0; i < running.length; i++) {
let app = running[i];
if (app.get_id() in favorites)
continue;
let display = new DockIcon(app,this);
icons++;
this.addItem(display.actor);
}
this._nicons=icons;
if (this._placeholderText) {
this._placeholderText.destroy();
this._placeholderText = null;
}
if (running.length == 0 && nFavorites == 0) {
this._placeholderText = new St.Label({ text: _("Drag here to add favorites") });
this.actor.add_actor(this._placeholderText);
}
let primary = Main.layoutManager.primaryMonitor;
let height = (icons)*(this._item_size + this._spacing) + 2*this._spacing;
let width = this._item_size + 4*this._spacing;
if (this._hideable && this._hidden) {
this._hideDock();
} else {
if (this._settings.get_int(DOCK_SIZE_KEY) == this._item_size) {
// only add/delete icon
this._showEffectAddItem ();
} else {
// change size icon
this._showDock ();
}
}
},
_getPreferredWidth: function (grid, forHeight, alloc) {
alloc.min_size = this._item_size;
alloc.natural_size = this._item_size + this._spacing;
},
_getPreferredHeight: function (grid, forWidth, alloc) {
let children = this._grid.get_children();
let nRows = children.length;
let totalSpacing = Math.max(0, nRows - 1) * this._spacing;
let height = nRows * this._item_size + totalSpacing;
alloc.min_size = height;
alloc.natural_size = height;
},
_allocate: function (grid, box, flags) {
let children = this._grid.get_children();
let x = box.x1 + this._spacing;
if (this._settings.get_enum(DOCK_POSITION_KEY) == PositionMode.LEFT)
x = box.x1 + 2*this._spacing;
let y = box.y1 + this._spacing;
for (let i = 0; i < children.length; i++) {
let childBox = new Clutter.ActorBox();
childBox.x1 = x;
childBox.y1 = y;
childBox.x2 = childBox.x1 + this._item_size;
childBox.y2 = childBox.y1 + this._item_size;
children[i].allocate(childBox, flags);
y += this._item_size + this._spacing;
}
},
_onStyleChanged: function() {
let themeNode = this.actor.get_theme_node();
let [success, len] = themeNode.get_length('spacing', false);
if (success)
this._spacing = len;
[success, len] = themeNode.get_length('-shell-grid-item-size', false);
if (success)
this._item_size = len;
this._grid.queue_relayout();
},
removeAll: function () {
this._grid.get_children().forEach(Lang.bind(this, function (child) {
child.destroy();
}));
},
addItem: function(actor) {
this._grid.add_actor(actor);
}
});
Signals.addSignalMethods(Dock.prototype);
const DockIcon = new Lang.Class({
Name: 'Dock.DockIcon',
_init : function(app, dock) {
this._dock = dock;
this._settings = dock._settings;
this.app = app;
this.actor = new St.Button({ style_class: 'app-well-app',
button_mask: St.ButtonMask.ONE | St.ButtonMask.TWO,
reactive: true,
x_fill: true,
y_fill: true });
this.actor._delegate = this;
this._icon = new AppDisplay.AppIcon(app, { setSizeManually: true,
showLabel: false });
this.actor.set_child(this._icon.actor);
this._icon.setIconSize(this._settings.get_int(DOCK_SIZE_KEY));
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
this._menu = null;
this._menuManager = new PopupMenu.PopupMenuManager(this);
this._has_focus = false;
let tracker = Shell.WindowTracker.get_default();
tracker.connect('notify::focus-app', Lang.bind(this, this._onStateChanged));
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
this.actor.connect('notify::hover', Lang.bind(this, this._hoverChanged));
this._menuTimeoutId = 0;
this._stateChangedId = this.app.connect('notify::state',
Lang.bind(this, this._onStateChanged));
this._onStateChanged();
},
_onDestroy: function() {
if (this._stateChangedId > 0)
this.app.disconnect(this._stateChangedId);
this._stateChangedId = 0;
this._removeMenuTimeout();
},
_removeMenuTimeout: function() {
if (this._menuTimeoutId > 0) {
Mainloop.source_remove(this._menuTimeoutId);
this._menuTimeoutId = 0;
}
},
_hoverChanged: function(actor) {
if (actor != this.actor)
this._has_focus = false;
else
this._has_focus = true;
return false;
},
_onStateChanged: function() {
let tracker = Shell.WindowTracker.get_default();
let focusedApp = tracker.focus_app;
if (this.app.state != Shell.AppState.STOPPED) {
this.actor.add_style_class_name('running');
if (this.app == focusedApp) {
this.actor.add_style_class_name('focused');
} else {
this.actor.remove_style_class_name('focused');
}
} else {
this.actor.remove_style_class_name('focused');
this.actor.remove_style_class_name('running');
}
},
_onButtonPress: function(actor, event) {
let button = event.get_button();
if (button == 1) {
this._removeMenuTimeout();
this._menuTimeoutId = Mainloop.timeout_add(AppDisplay.MENU_POPUP_TIMEOUT, Lang.bind(this, function() {
this.popupMenu();
}));
} else if (button == 3) {
this.popupMenu();
}
},
_onClicked: function(actor, button) {
this._removeMenuTimeout();
if (button == 1) {
this._onActivate(Clutter.get_current_event());
} else if (button == 2) {
// Last workspace is always empty
let launchWorkspace = global.screen.get_workspace_by_index(global.screen.n_workspaces - 1);
launchWorkspace.activate(global.get_current_time());
this.emit('launching');
this.app.open_new_window(-1);
}
return false;
},
getId: function() {
return this.app.get_id();
},
popupMenu: function() {
this._removeMenuTimeout();
this.actor.fake_release();
this._dock._disableHideDock();
if (!this._menu) {
this._menu = new DockIconMenu(this);
this._menu.connect('activate-window', Lang.bind(this, function (menu, window) {
this.activateWindow(window);
}));
this._menu.connect('open-state-changed', Lang.bind(this, function (menu, isPoppedUp) {
if (!isPoppedUp){
//Restore value of autohidedock
this._dock._restoreHideDock();
this._dock._hideDock();
this._onMenuPoppedDown();
}
}));
this._menuManager.addMenu(this._menu, true);
}
this._menu.redisplay();
this._menu.open();
return false;
},
activateWindow: function(metaWindow) {
if (metaWindow) {
this._didActivateWindow = true;
Main.activateWindow(metaWindow);
}
},
setSelected: function (isSelected) {
this._selected = isSelected;
if (this._selected)
this.actor.add_style_class_name('selected');
else
this.actor.remove_style_class_name('selected');
},
_onMenuPoppedDown: function() {
this.actor.sync_hover();
},
_getRunning: function() {
return this.app.state != Shell.AppState.STOPPED;
},
_onActivate: function (event) {
this.emit('launching');
let modifiers = event.get_state();
if (modifiers & Clutter.ModifierType.CONTROL_MASK
&& this.app.state == Shell.AppState.RUNNING) {
let current_workspace = global.screen.get_active_workspace().index();
this.app.open_new_window(current_workspace);
} else {
let tracker = Shell.WindowTracker.get_default();
let focusedApp = tracker.focus_app;
if (this.app == focusedApp) {
let windows = this.app.get_windows();
let current_workspace = global.screen.get_active_workspace();
for (let i = 0; i < windows.length; i++) {
let w = windows[i];
if (w.get_workspace() == current_workspace)
w.minimize();
}
} else {
this.app.activate(-1);
}
}
Main.overview.hide();
}
});
Signals.addSignalMethods(DockIcon.prototype);
const DockIconMenu = new Lang.Class({
Name: 'Dock.DockIconMenu',
Extends: PopupMenu.PopupMenu,
_init: function(source) {
let side;
switch (source._settings.get_enum(DOCK_POSITION_KEY)) {
case PositionMode.LEFT:
side = St.Side.LEFT;
break;
case PositionMode.RIGHT:
default:
side = St.Side.RIGHT;
}
this.parent(source.actor, 0.5, side);
this._source = source;
this.connect('activate', Lang.bind(this, this._onActivate));
this.actor.add_style_class_name('dock-menu');
// Chain our visibility and lifecycle to that of the source
source.actor.connect('notify::mapped', Lang.bind(this, function () {
if (!source.actor.mapped)
this.close();
}));
source.actor.connect('destroy', Lang.bind(this, function () { this.destroy(); }));
Main.layoutManager.addChrome(this.actor);
},
redisplay: function() {
this.removeAll();
let windows = this._source.app.get_windows();
// Display the app windows menu items and the separator between windows
// of the current desktop and other windows.
let activeWorkspace = global.screen.get_active_workspace();
let separatorShown = windows.length > 0 && windows[0].get_workspace() != activeWorkspace;
for (let i = 0; i < windows.length; i++) {
if (!separatorShown && windows[i].get_workspace() != activeWorkspace) {
this._appendSeparator();
separatorShown = true;
}
let item = this._appendMenuItem(windows[i].title);
item._window = windows[i];
}
if (windows.length > 0)
this._appendSeparator();
let isFavorite = AppFavorites.getAppFavorites().isFavorite(this._source.app.get_id());
this._newWindowMenuItem = windows.length > 0 ? this._appendMenuItem(_("New Window")) : null;
this._quitAppMenuItem = windows.length >0 ? this._appendMenuItem(_("Quit Application")) : null;
if (windows.length > 0)
this._appendSeparator();
this._toggleFavoriteMenuItem = this._appendMenuItem(isFavorite ?
_("Remove from Favorites")
: _("Add to Favorites"));
this._highlightedItem = null;
},
_appendSeparator: function () {
let separator = new PopupMenu.PopupSeparatorMenuItem();
this.addMenuItem(separator);
},
_appendMenuItem: function(labelText) {
// FIXME: app-well-menu-item style
let item = new PopupMenu.PopupMenuItem(labelText);
this.addMenuItem(item);
return item;
},
popup: function(activatingButton) {
this._redisplay();
this.open();
},
_onActivate: function (actor, child) {
if (child._window) {
let metaWindow = child._window;
this.emit('activate-window', metaWindow);
} else if (child == this._newWindowMenuItem) {
let current_workspace = global.screen.get_active_workspace().index();
this._source.app.open_new_window(current_workspace);
this.emit('activate-window', null);
} else if (child == this._quitAppMenuItem) {
this._source.app.request_quit();
} else if (child == this._toggleFavoriteMenuItem) {
let favs = AppFavorites.getAppFavorites();
let isFavorite = favs.isFavorite(this._source.app.get_id());
if (isFavorite)
favs.removeFavorite(this._source.app.get_id());
else
favs.addFavorite(this._source.app.get_id());
}
this.close();
}
});
function init() {
Convenience.initTranslations();
}
let dock;
function enable() {
dock = new Dock();
}
function disable() {
dock.destroy();
dock = null;
}