Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • manjaro-arm/applications/arm-profiles
  • luka177/arm-profiles
  • boredland/arm-profiles
3 results
Show changes
Showing
with 188 additions and 8104 deletions
/*
* This file is part of the Dash-To-Panel extension for Gnome 3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Credits:
* This file is based on code from the Dash to Dock extension by micheleg
* and code from the Taskbar extension by Zorin OS
*
* Code to re-anchor the panel was taken from Thoma5 BottomPanel:
* https://github.com/Thoma5/gnome-shell-extension-bottompanel
*
* Pattern for moving clock based on Frippery Move Clock by R M Yorston
* http://frippery.org/extensions/
*
* Some code was also adapted from the upstream Gnome Shell source code.
*/
const Me = imports.misc.extensionUtils.getCurrentExtension();
const Overview = Me.imports.overview;
const Panel = Me.imports.panel;
const Proximity = Me.imports.proximity;
const Taskbar = Me.imports.taskbar;
const Utils = Me.imports.utils;
const Lang = imports.lang;
const Gi = imports._gi;
const Clutter = imports.gi.Clutter;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const BoxPointer = imports.ui.boxpointer;
const Dash = imports.ui.dash;
const IconGrid = imports.ui.iconGrid;
const LookingGlass = imports.ui.lookingGlass;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const Layout = imports.ui.layout;
const WorkspacesView = imports.ui.workspacesView;
var dtpPanelManager = Utils.defineClass({
Name: 'DashToPanel.PanelManager',
_init: function() {
this.overview = new Overview.dtpOverview();
Main.overview.viewSelector.appDisplay._views.forEach(v => Utils.wrapActor(v.view._grid));
},
enable: function(reset) {
let dtpPrimaryIndex = Me.settings.get_int('primary-monitor');
if(dtpPrimaryIndex < 0 || dtpPrimaryIndex >= Main.layoutManager.monitors.length)
dtpPrimaryIndex = Main.layoutManager.primaryIndex;
let dtpPrimaryMonitor = Main.layoutManager.monitors[dtpPrimaryIndex];
this.proximityManager = new Proximity.ProximityManager();
Utils.wrapActor(Main.panel);
Main.panel.actor.hide();
this.primaryPanel = this._createPanel(dtpPrimaryMonitor);
this.allPanels = [ this.primaryPanel ];
this.overview.enable(this.primaryPanel);
if (Me.settings.get_boolean('multi-monitors')) {
Main.layoutManager.monitors.filter(m => m != dtpPrimaryMonitor).forEach(m => {
this.allPanels.push(this._createPanel(m, true));
});
}
global.dashToPanel.panels = this.allPanels;
global.dashToPanel.emit('panels-created');
let panelPosition = Panel.getPosition();
this.allPanels.forEach(p => {
let leftOrRight = (panelPosition == St.Side.LEFT || panelPosition == St.Side.RIGHT);
p.panelBox.set_size(
leftOrRight ? -1 : p.monitor.width,
leftOrRight ? p.monitor.height : -1
);
this._findPanelMenuButtons(p.panelBox).forEach(pmb => this._adjustPanelMenuButton(pmb, p.monitor, panelPosition));
});
//in 3.32, BoxPointer now inherits St.Widget
if (BoxPointer.BoxPointer.prototype.vfunc_get_preferred_height) {
let panelManager = this;
Utils.hookVfunc(BoxPointer.BoxPointer.prototype, 'get_preferred_height', function(forWidth) {
let alloc = { min_size: 0, natural_size: 0 };
[alloc.min_size, alloc.natural_size] = this.vfunc_get_preferred_height(forWidth);
return panelManager._getBoxPointerPreferredHeight(this, alloc);
});
}
this.setFocusedMonitor(dtpPrimaryMonitor);
if (reset) return;
this._oldViewSelectorAnimateIn = Main.overview.viewSelector._animateIn;
Main.overview.viewSelector._animateIn = Lang.bind(this.primaryPanel, newViewSelectorAnimateIn);
this._oldViewSelectorAnimateOut = Main.overview.viewSelector._animateOut;
Main.overview.viewSelector._animateOut = Lang.bind(this.primaryPanel, newViewSelectorAnimateOut);
this._oldUpdatePanelBarrier = Main.layoutManager._updatePanelBarrier;
Main.layoutManager._updatePanelBarrier = (panel) => {
let panelUpdates = panel ? [panel] : this.allPanels;
panelUpdates.forEach(p => newUpdatePanelBarrier.call(Main.layoutManager, p));
};
Main.layoutManager._updatePanelBarrier();
this._oldUpdateHotCorners = Main.layoutManager._updateHotCorners;
Main.layoutManager._updateHotCorners = Lang.bind(Main.layoutManager, newUpdateHotCorners);
Main.layoutManager._updateHotCorners();
if (Main.layoutManager._interfaceSettings) {
this._enableHotCornersId = Main.layoutManager._interfaceSettings.connect('changed::enable-hot-corners', () => Main.layoutManager._updateHotCorners());
}
this._oldOverviewRelayout = Main.overview._relayout;
Main.overview._relayout = Lang.bind(Main.overview, this._newOverviewRelayout);
this._oldUpdateWorkspacesViews = Main.overview.viewSelector._workspacesDisplay._updateWorkspacesViews;
Main.overview.viewSelector._workspacesDisplay._updateWorkspacesViews = Lang.bind(Main.overview.viewSelector._workspacesDisplay, this._newUpdateWorkspacesViews);
this._oldGetShowAppsButton = Main.overview.getShowAppsButton;
Main.overview.getShowAppsButton = this._newGetShowAppsButton.bind(this);
this._needsDashItemContainerAllocate = !Dash.DashItemContainer.prototype.hasOwnProperty('vfunc_allocate');
if (this._needsDashItemContainerAllocate) {
Utils.hookVfunc(Dash.DashItemContainer.prototype, 'allocate', this._newDashItemContainerAllocate);
}
// Since Gnome 3.8 dragging an app without having opened the overview before cause the attemp to
//animate a null target since some variables are not initialized when the viewSelector is created
if(Main.overview.viewSelector._activePage == null)
Main.overview.viewSelector._activePage = Main.overview.viewSelector._workspacesPage;
LookingGlass.LookingGlass.prototype._oldResize = LookingGlass.LookingGlass.prototype._resize;
LookingGlass.LookingGlass.prototype._resize = _newLookingGlassResize;
LookingGlass.LookingGlass.prototype._oldOpen = LookingGlass.LookingGlass.prototype.open;
LookingGlass.LookingGlass.prototype.open = _newLookingGlassOpen;
//listen settings
this._signalsHandler = new Utils.GlobalSignalsHandler();
this._signalsHandler.add(
[
Me.settings,
[
'changed::primary-monitor',
'changed::multi-monitors',
'changed::isolate-monitors',
'changed::taskbar-position',
'changed::panel-position'
],
() => this._reset()
],
[
Me.settings,
'changed::intellihide-key-toggle-text',
() => this._setKeyBindings(true)
],
[
Utils.DisplayWrapper.getMonitorManager(),
'monitors-changed',
() => {
if (Main.layoutManager.primaryMonitor) {
this._reset();
}
}
]
);
['_leftBox', '_centerBox', '_rightBox'].forEach(c => this._signalsHandler.add(
[Main.panel[c], 'actor-added', (parent, child) => this._adjustPanelMenuButton(this._getPanelMenuButton(child), this.primaryPanel.monitor, Panel.getPosition())]
));
this._setKeyBindings(true);
},
disable: function(reset) {
this.overview.disable();
this.proximityManager.destroy();
this.allPanels.forEach(p => {
this._findPanelMenuButtons(p.panelBox).forEach(pmb => {
if (pmb.menu._boxPointer._dtpGetPreferredHeightId) {
pmb.menu._boxPointer._container.disconnect(pmb.menu._boxPointer._dtpGetPreferredHeightId);
}
pmb.menu._boxPointer.sourceActor = pmb.menu._boxPointer._dtpSourceActor;
delete pmb.menu._boxPointer._dtpSourceActor;
pmb.menu._boxPointer._userArrowSide = St.Side.TOP;
})
this._removePanelBarriers(p);
p.disable();
Main.layoutManager.removeChrome(p.panelBox);
p.panelBox.destroy();
});
if (BoxPointer.BoxPointer.prototype.vfunc_get_preferred_height) {
Utils.hookVfunc(BoxPointer.BoxPointer.prototype, 'get_preferred_height', BoxPointer.BoxPointer.prototype.vfunc_get_preferred_height);
}
if (reset) return;
this._setKeyBindings(false);
this._signalsHandler.destroy();
Main.layoutManager._updateHotCorners = this._oldUpdateHotCorners;
Main.layoutManager._updateHotCorners();
if (this._enableHotCornersId) {
Main.layoutManager._interfaceSettings.disconnect(this._enableHotCornersId);
}
Main.layoutManager._updatePanelBarrier = this._oldUpdatePanelBarrier;
Main.layoutManager._updatePanelBarrier();
Main.overview.viewSelector._animateIn = this._oldViewSelectorAnimateIn;
Main.overview.viewSelector._animateOut = this._oldViewSelectorAnimateOut;
Main.overview._relayout = this._oldOverviewRelayout;
Main.overview._relayout();
Main.overview.viewSelector._workspacesDisplay._updateWorkspacesViews = this._oldUpdateWorkspacesViews;
Main.overview.getShowAppsButton = this._oldGetShowAppsButton;
Main.overview._panelGhost.set_height(Main.panel.actor.height);
Main.panel.actor.show();
if (this._needsDashItemContainerAllocate) {
Utils.hookVfunc(Dash.DashItemContainer.prototype, 'allocate', function(box, flags) { this.vfunc_allocate(box, flags); });
}
LookingGlass.LookingGlass.prototype._resize = LookingGlass.LookingGlass.prototype._oldResize;
delete LookingGlass.LookingGlass.prototype._oldResize;
LookingGlass.LookingGlass.prototype.open = LookingGlass.LookingGlass.prototype._oldOpen;
delete LookingGlass.LookingGlass.prototype._oldOpen
},
setFocusedMonitor: function(monitor, ignoreRelayout) {
if (!this.checkIfFocusedMonitor(monitor)) {
Main.overview.viewSelector._workspacesDisplay._primaryIndex = monitor.index;
Main.overview._overview.clear_constraints();
Main.overview._overview.add_constraint(new Layout.MonitorConstraint({ index: monitor.index }));
if (ignoreRelayout) return;
this._newOverviewRelayout.call(Main.overview);
}
},
checkIfFocusedMonitor: function(monitor) {
return Main.overview.viewSelector._workspacesDisplay._primaryIndex == monitor.index;
},
_createPanel: function(monitor, isSecondary) {
let panelBox = new St.BoxLayout({ name: 'panelBox' });
let panel = new Panel.dtpPanel(this, monitor, panelBox, isSecondary);
panelBox.add(panel.bg);
Main.layoutManager.addChrome(panelBox, { affectsStruts: true, trackFullscreen: true });
panel.enable();
return panel;
},
_reset: function() {
this.disable(true);
this.allPanels = [];
this.enable(true);
},
_adjustPanelMenuButton: function(button, monitor, arrowSide) {
if (button) {
Utils.wrapActor(button);
button.menu._boxPointer._dtpSourceActor = button.menu._boxPointer.sourceActor;
button.menu._boxPointer.sourceActor = button.actor;
button.menu._boxPointer._userArrowSide = arrowSide;
button.menu._boxPointer._dtpInPanel = 1;
if (!button.menu._boxPointer.vfunc_get_preferred_height) {
button.menu._boxPointer._dtpGetPreferredHeightId = button.menu._boxPointer._container.connect('get-preferred-height', (actor, forWidth, alloc) => {
this._getBoxPointerPreferredHeight(button.menu._boxPointer, alloc, monitor);
});
}
}
},
_getBoxPointerPreferredHeight: function(boxPointer, alloc, monitor) {
if (boxPointer._dtpInPanel && boxPointer.sourceActor && Me.settings.get_boolean('intellihide')) {
monitor = monitor || Main.layoutManager.findMonitorForActor(boxPointer.sourceActor);
let excess = alloc.natural_size + Panel.size + 10 - monitor.height; // 10 is arbitrary
if (excess > 0) {
alloc.natural_size -= excess;
}
}
return [alloc.min_size, alloc.natural_size];
},
_findPanelMenuButtons: function(container) {
let panelMenuButtons = [];
let panelMenuButton;
let find = parent => parent.get_children().forEach(c => {
if ((panelMenuButton = this._getPanelMenuButton(c))) {
panelMenuButtons.push(panelMenuButton);
}
find(c);
});
find(container);
return panelMenuButtons;
},
_removePanelBarriers: function(panel) {
if (panel.isSecondary && panel._rightPanelBarrier) {
panel._rightPanelBarrier.destroy();
}
if (panel._leftPanelBarrier) {
panel._leftPanelBarrier.destroy();
delete panel._leftPanelBarrier;
}
},
_getPanelMenuButton: function(obj) {
return obj._delegate && obj._delegate instanceof PanelMenu.Button ? obj._delegate : 0;
},
_setKeyBindings: function(enable) {
let keys = {
'intellihide-key-toggle': () => this.allPanels.forEach(p => p.intellihide.toggle())
};
Object.keys(keys).forEach(k => {
Utils.removeKeybinding(k);
if (enable) {
Utils.addKeybinding(k, Me.settings, keys[k], Shell.ActionMode.NORMAL);
}
});
},
_newOverviewRelayout: function() {
// To avoid updating the position and size of the workspaces
// we just hide the overview. The positions will be updated
// when it is next shown.
this.hide();
let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.overview.viewSelector._workspacesDisplay._primaryIndex);
this._coverPane.set_position(0, workArea.y);
this._coverPane.set_size(workArea.width, workArea.height);
this._updateBackgrounds();
},
_newUpdateWorkspacesViews: function() {
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].destroy();
this._workspacesViews = [];
let monitors = Main.layoutManager.monitors;
for (let i = 0; i < monitors.length; i++) {
let view;
if (this._workspacesOnlyOnPrimary && i != Main.layoutManager.primaryIndex) {
view = new WorkspacesView.ExtraWorkspaceView(i);
view.getActiveWorkspace = view.getActiveWorkspace || function() { return this._workspace; };
} else
view = new WorkspacesView.WorkspacesView(i);
view.actor.connect('scroll-event', this._onScrollEvent.bind(this));
if (i == Main.layoutManager.primaryIndex && view.scrollAdjustment) {
this._scrollAdjustment = view.scrollAdjustment;
this._scrollAdjustment.connect('notify::value',
this._scrollValueChanged.bind(this));
}
this._workspacesViews.push(view);
}
this._workspacesViews.forEach(wv => Main.layoutManager.overviewGroup.add_actor(wv.actor));
this._updateWorkspacesFullGeometry();
this._updateWorkspacesActualGeometry();
},
_newGetShowAppsButton: function() {
let focusedMonitorIndex = Utils.findIndex(this.allPanels, p => this.checkIfFocusedMonitor(p.monitor));
return this.allPanels[focusedMonitorIndex].taskbar.showAppsButton;
},
_newDashItemContainerAllocate: function(box, flags) {
if (this.child == null)
return;
this.set_allocation(box, flags);
let availWidth = box.x2 - box.x1;
let availHeight = box.y2 - box.y1;
let [minChildWidth, minChildHeight, natChildWidth, natChildHeight] = this.child.get_preferred_size();
let [childScaleX, childScaleY] = this.child.get_scale();
let childWidth = Math.min(natChildWidth * childScaleX, availWidth);
let childHeight = Math.min(natChildHeight * childScaleY, availHeight);
let childBox = new Clutter.ActorBox();
childBox.x1 = (availWidth - childWidth) / 2;
childBox.y1 = (availHeight - childHeight) / 2;
childBox.x2 = childBox.x1 + childWidth;
childBox.y2 = childBox.y1 + childHeight;
this.child.allocate(childBox, flags);
},
});
function newViewSelectorAnimateIn(oldPage) {
if (oldPage)
oldPage.hide();
let vs = Main.overview.viewSelector;
vs.emit('page-empty');
vs._activePage.show();
if (vs._activePage == vs._appsPage && oldPage == vs._workspacesPage) {
// Restore opacity, in case we animated via _fadePageOut
vs._activePage.opacity = 255;
let animate = Me.settings.get_boolean('animate-show-apps');
if(animate)
vs.appDisplay.animate(IconGrid.AnimationDirection.IN);
} else {
vs._fadePageIn();
}
}
function newViewSelectorAnimateOut(page) {
let oldPage = page;
let vs = Main.overview.viewSelector;
if (page == vs._appsPage &&
vs._activePage == vs._workspacesPage &&
!Main.overview.animationInProgress) {
let animate = Me.settings.get_boolean('animate-show-apps');
if(animate)
vs.appDisplay.animate(IconGrid.AnimationDirection.OUT, Lang.bind(this,
function() {
vs._animateIn(oldPage)
}));
else
vs._animateIn(oldPage)
} else {
vs._fadePageOut(page);
}
}
function newUpdateHotCorners() {
// destroy old hot corners
this.hotCorners.forEach(function(corner) {
if (corner)
corner.destroy();
});
this.hotCorners = [];
//global.settings is ubuntu specific setting to disable the hot corner (Tweak tool > Top Bar > Activities Overview Hot Corner)
//this._interfaceSettings is for the setting to disable the hot corner introduced in gnome-shell 3.34
if ((global.settings.list_keys().indexOf('enable-hot-corners') >= 0 && !global.settings.get_boolean('enable-hot-corners')) ||
(this._interfaceSettings && !this._interfaceSettings.get_boolean('enable-hot-corners'))) {
this.emit('hot-corners-changed');
return;
}
let panelPosition = Panel.getPosition();
// build new hot corners
for (let i = 0; i < this.monitors.length; i++) {
let monitor = this.monitors[i];
let cornerX = this._rtl ? monitor.x + monitor.width : monitor.x;
let cornerY = monitor.y;
let haveTopLeftCorner = true;
// If the panel is on the bottom, don't add a topleft hot corner unless it is actually
// a top left panel. Otherwise, it stops the mouse as you are dragging across
// In the future, maybe we will automatically move the hotcorner to the bottom
// when the panel is positioned at the bottom
if (i != this.primaryIndex || panelPosition == St.Side.BOTTOM || panelPosition == St.Side.RIGHT) {
// Check if we have a top left (right for RTL) corner.
// I.e. if there is no monitor directly above or to the left(right)
let besideX = this._rtl ? monitor.x + 1 : cornerX - 1;
let besideY = cornerY;
let aboveX = cornerX;
let aboveY = cornerY - 1;
for (let j = 0; j < this.monitors.length; j++) {
if (i == j)
continue;
let otherMonitor = this.monitors[j];
if (besideX >= otherMonitor.x &&
besideX < otherMonitor.x + otherMonitor.width &&
besideY >= otherMonitor.y &&
besideY < otherMonitor.y + otherMonitor.height) {
haveTopLeftCorner = false;
break;
}
if (aboveX >= otherMonitor.x &&
aboveX < otherMonitor.x + otherMonitor.width &&
aboveY >= otherMonitor.y &&
aboveY < otherMonitor.y + otherMonitor.height) {
haveTopLeftCorner = false;
break;
}
}
}
if (haveTopLeftCorner) {
let corner = new Layout.HotCorner(this, monitor, cornerX, cornerY);
corner.setBarrierSize(Panel.size);
this.hotCorners.push(corner);
} else {
this.hotCorners.push(null);
}
}
this.emit('hot-corners-changed');
}
function newUpdatePanelBarrier(panel) {
if (this._rightPanelBarrier) {
this._rightPanelBarrier.destroy();
}
let barriers = {
_rightPanelBarrier: [],
_leftPanelBarrier: []
};
Object.keys(barriers).forEach(k => {
if (panel[k]) {
panel[k].destroy();
panel[k] = null;
}
});
if (!this.primaryMonitor || !panel.panelBox.height) {
return;
}
let barrierSize = Math.min(10, panel.panelBox.height);
let fixed1 = panel.monitor.y;
let fixed2 = panel.monitor.y + barrierSize;
if (Panel.checkIfVertical()) {
barriers._rightPanelBarrier.push(panel.monitor.y + panel.monitor.height, Meta.BarrierDirection.POSITIVE_Y);
barriers._leftPanelBarrier.push(panel.monitor.y, Meta.BarrierDirection.NEGATIVE_Y);
} else {
barriers._rightPanelBarrier.push(panel.monitor.x + panel.monitor.width, Meta.BarrierDirection.NEGATIVE_X);
barriers._leftPanelBarrier.push(panel.monitor.x, Meta.BarrierDirection.POSITIVE_X);
}
switch (Panel.getPosition()) {
//values are initialized as St.Side.TOP
case St.Side.BOTTOM:
fixed1 = panel.monitor.y + panel.monitor.height - barrierSize;
fixed2 = panel.monitor.y + panel.monitor.height;
break;
case St.Side.LEFT:
fixed1 = panel.monitor.x;
fixed2 = panel.monitor.x + barrierSize;
break;
case St.Side.RIGHT:
fixed1 = panel.monitor.x + panel.monitor.width;
fixed2 = panel.monitor.x + panel.monitor.width - barrierSize;
break;
}
//remove left barrier if it overlaps one of the hotcorners
for (let k in this.hotCorners) {
let hc = this.hotCorners[k];
if (hc && hc._monitor == panel.monitor &&
((fixed1 == hc._x || fixed2 == hc._x) || fixed1 == hc._y || fixed2 == hc._y)) {
delete barriers._leftPanelBarrier;
break;
}
}
Object.keys(barriers).forEach(k => {
let barrierOptions = {
display: global.display,
directions: barriers[k][1]
};
barrierOptions[Panel.varCoord.c1] = barrierOptions[Panel.varCoord.c2] = barriers[k][0];
barrierOptions[Panel.fixedCoord.c1] = fixed1;
barrierOptions[Panel.fixedCoord.c2] = fixed2;
panel[k] = new Meta.Barrier(barrierOptions);
});
}
function _newLookingGlassResize() {
this._oldResize();
if (Panel.getPosition() == St.Side.TOP) {
this._hiddenY = Main.layoutManager.primaryMonitor.y + Panel.size - this.actor.height;
this._targetY = this._hiddenY + this.actor.height;
this.actor.y = this._hiddenY;
this._objInspector.actor.set_position(this.actor.x + Math.floor(this.actor.width * 0.1), this._targetY + Math.floor(this.actor.height * 0.1));
}
}
function _newLookingGlassOpen() {
if (this._open)
return;
this._resize();
this._oldOpen();
}
\ No newline at end of file
/*
* This file is part of the Dash-To-Panel extension for Gnome 3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Credits:
* Ideas for recursing child actors and assigning inline styles
* are based on code from the StatusAreaHorizontalSpacing extension
* https://bitbucket.org/mathematicalcoffee/status-area-horizontal-spacing-gnome-shell-extension
* mathematical.coffee@gmail.com
*/
const Me = imports.misc.extensionUtils.getCurrentExtension();
const ExtensionUtils = imports.misc.extensionUtils;
const Lang = imports.lang;
const Main = imports.ui.main;
const Mainloop = imports.mainloop;
const St = imports.gi.St;
const Shell = imports.gi.Shell;
const Panel = Me.imports.panel;
const Taskbar = Me.imports.taskbar;
const Utils = Me.imports.utils;
var dtpPanelStyle = Utils.defineClass({
Name: 'DashToPanel.PanelStyle',
_init: function() {
},
enable : function(panel) {
this.panel = panel;
this._applyStyles();
this._bindSettingsChanges();
},
disable: function () {
for (let i = 0; i < this._dtpSettingsSignalIds.length; ++i) {
Me.settings.disconnect(this._dtpSettingsSignalIds[i]);
}
this._removeStyles();
},
_bindSettingsChanges: function() {
let configKeys = [
"tray-size",
"leftbox-size",
"tray-padding",
"leftbox-padding",
"status-icon-padding",
];
this._dtpSettingsSignalIds = [];
for(let i in configKeys) {
this._dtpSettingsSignalIds.push(Me.settings.connect('changed::' + configKeys[i], Lang.bind(this, function () {
this._removeStyles();
this._applyStyles();
})));
}
},
_applyStyles: function() {
this._rightBoxOperations = [];
let trayPadding = Me.settings.get_int('tray-padding');
let isVertical = Panel.checkIfVertical();
let paddingStyle = 'padding: ' + (isVertical ? '%dpx 0' : '0 %dpx');
if(trayPadding >= 0) {
let operation = {};
let trayPaddingStyleLine;
if (isVertical) {
trayPaddingStyleLine = paddingStyle.format(trayPadding);
operation.compareFn = function (actor) {
let parent = actor.get_parent();
return (parent && parent.has_style_class_name && parent.has_style_class_name('panel-button'));
};
} else {
trayPaddingStyleLine = '-natural-hpadding: %dpx'.format(trayPadding);
if (trayPadding < 6) {
trayPaddingStyleLine += '; -minimum-hpadding: %dpx'.format(trayPadding);
}
operation.compareFn = function (actor) {
return (actor.has_style_class_name && actor.has_style_class_name('panel-button'));
};
}
operation.applyFn = Lang.bind(this, function (actor, operationIdx) {
this._overrideStyle(actor, trayPaddingStyleLine, operationIdx);
this._refreshPanelButton(actor);
});
this._rightBoxOperations.push(operation);
}
let statusIconPadding = Me.settings.get_int('status-icon-padding');
if(statusIconPadding >= 0) {
let statusIconPaddingStyleLine = paddingStyle.format(statusIconPadding)
let operation = {};
operation.compareFn = function (actor) {
return (actor.has_style_class_name && actor.has_style_class_name('system-status-icon'));
};
operation.applyFn = Lang.bind(this, function (actor, operationIdx) {
this._overrideStyle(actor, statusIconPaddingStyleLine, operationIdx);
});
this._rightBoxOperations.push(operation);
}
let trayContentSize = Me.settings.get_int('tray-size');
if(trayContentSize > 0) {
let trayIconSizeStyleLine = 'icon-size: %dpx'.format(trayContentSize)
let operation = {};
operation.compareFn = function (actor) {
return (actor.constructor && actor.constructor.name == 'St_Icon');
};
operation.applyFn = Lang.bind(this, function (actor, operationIdx) {
this._overrideStyle(actor, trayIconSizeStyleLine, operationIdx);
});
this._rightBoxOperations.push(operation);
let trayContentSizeStyleLine = 'font-size: %dpx'.format(trayContentSize)
operation = {};
operation.compareFn = function (actor) {
return (actor.constructor && actor.constructor.name == 'St_Label');
};
operation.applyFn = Lang.bind(this, function (actor, operationIdx) {
this._overrideStyle(actor, trayContentSizeStyleLine, operationIdx);
});
this._rightBoxOperations.push(operation);
this._overrideStyle(this.panel._rightBox, trayContentSizeStyleLine, 0);
this._overrideStyle(this.panel._centerBox, trayContentSizeStyleLine, 0);
}
// center box has been moved next to the right box and will be treated the same
this._centerBoxOperations = this._rightBoxOperations;
this._leftBoxOperations = [];
let leftboxPadding = Me.settings.get_int('leftbox-padding');
if(leftboxPadding >= 0) {
let leftboxPaddingStyleLine = paddingStyle.format(leftboxPadding);
let operation = {};
operation.compareFn = function (actor) {
let parent = actor.get_parent();
return (parent && parent.has_style_class_name && parent.has_style_class_name('panel-button'));
};
operation.applyFn = Lang.bind(this, function (actor, operationIdx) {
this._overrideStyle(actor, leftboxPaddingStyleLine, operationIdx);
});
this._leftBoxOperations.push(operation);
}
let leftboxContentSize = Me.settings.get_int('leftbox-size');
if(leftboxContentSize > 0) {
let leftboxIconSizeStyleLine = 'icon-size: %dpx'.format(leftboxContentSize)
let operation = {};
operation.compareFn = function (actor) {
return (actor.constructor && actor.constructor.name == 'St_Icon');
};
operation.applyFn = Lang.bind(this, function (actor, operationIdx) {
this._overrideStyle(actor, leftboxIconSizeStyleLine, operationIdx);
});
this._leftBoxOperations.push(operation);
let leftboxContentSizeStyleLine = 'font-size: %dpx'.format(leftboxContentSize)
operation = {};
operation.compareFn = function (actor) {
return (actor.constructor && actor.constructor.name == 'St_Label');
};
operation.applyFn = Lang.bind(this, function (actor, operationIdx) {
this._overrideStyle(actor, leftboxContentSizeStyleLine, operationIdx);
});
this._leftBoxOperations.push(operation);
this._overrideStyle(this.panel._leftBox, leftboxContentSizeStyleLine, 0);
}
/*recurse actors */
if(this._rightBoxOperations.length) {
let children = this.panel._rightBox.get_children();
for(let i in children)
this._recursiveApply(children[i], this._rightBoxOperations);
}
if(this._centerBoxOperations.length) {
let children = this.panel._centerBox.get_children();
for(let i in children)
this._recursiveApply(children[i], this._centerBoxOperations);
}
if(this._leftBoxOperations.length) {
let children = this.panel._leftBox.get_children();
for(let i in children)
this._recursiveApply(children[i], this._leftBoxOperations);
}
/* connect signal */
this._rightBoxActorAddedID = this.panel._rightBox.connect('actor-added',
Lang.bind(this, function (container, actor) {
if(this._rightBoxOperations.length)
this._recursiveApply(actor, this._rightBoxOperations);
})
);
this._centerBoxActorAddedID = this.panel._centerBox.connect('actor-added',
Lang.bind(this, function (container, actor) {
if(this._centerBoxOperations.length)
this._recursiveApply(actor, this._centerBoxOperations);
})
);
this._leftBoxActorAddedID = this.panel._leftBox.connect('actor-added',
Lang.bind(this, function (container, actor) {
if(this._leftBoxOperations.length)
this._recursiveApply(actor, this._leftBoxOperations);
})
);
},
_removeStyles: function() {
/* disconnect signal */
if (this._rightBoxActorAddedID)
this.panel._rightBox.disconnect(this._rightBoxActorAddedID);
if (this._centerBoxActorAddedID)
this.panel._centerBox.disconnect(this._centerBoxActorAddedID);
if (this._leftBoxActorAddedID)
this.panel._leftBox.disconnect(this._leftBoxActorAddedID);
this._restoreOriginalStyle(this.panel._rightBox);
if(this._rightBoxOperations.length) {
let children = this.panel._rightBox.get_children();
for(let i in children)
this._recursiveApply(children[i], this._rightBoxOperations, true);
}
this._restoreOriginalStyle(this.panel._centerBox);
if(this._centerBoxOperations.length) {
let children = this.panel._centerBox.get_children();
for(let i in children)
this._recursiveApply(children[i], this._centerBoxOperations, true);
}
this._restoreOriginalStyle(this.panel._leftBox);
if(this._leftBoxOperations.length) {
let children = this.panel._leftBox.get_children();
for(let i in children)
this._recursiveApply(children[i], this._leftBoxOperations, true);
}
},
_recursiveApply: function(actor, operations, restore) {
for(let i in operations) {
let o = operations[i];
if(o.compareFn(actor))
if(restore)
o.restoreFn ? o.restoreFn(actor) : this._restoreOriginalStyle(actor);
else
o.applyFn(actor, i);
}
if(actor.get_children) {
let children = actor.get_children();
for(let i in children) {
this._recursiveApply(children[i], operations, restore);
}
}
},
_overrideStyle: function(actor, styleLine, operationIdx) {
if (actor._dtp_original_inline_style === undefined) {
actor._dtp_original_inline_style = actor.get_style();
}
if(actor._dtp_style_overrides === undefined) {
actor._dtp_style_overrides = {};
}
actor._dtp_style_overrides[operationIdx] = styleLine;
let newStyleLine = '';
for(let i in actor._dtp_style_overrides)
newStyleLine += actor._dtp_style_overrides[i] + '; ';
actor.set_style(newStyleLine + (actor._dtp_original_inline_style || ''));
},
_restoreOriginalStyle: function(actor) {
if (actor._dtp_original_inline_style !== undefined) {
actor.set_style(actor._dtp_original_inline_style);
delete actor._dtp_original_inline_style;
delete actor._dtp_style_overrides;
}
if (actor.has_style_class_name('panel-button')) {
this._refreshPanelButton(actor);
}
},
_refreshPanelButton: function(actor) {
if (actor.visible && imports.misc.config.PACKAGE_VERSION >= '3.34.0') {
//force gnome 3.34 to refresh (having problem with the -natural-hpadding)
actor.hide();
Mainloop.idle_add(() => actor.show());
}
}
});
/*
* This file is part of the Dash-To-Panel extension for Gnome 3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
* Credits:
* This file is based on code from the Dash to Dock extension by micheleg.
* Some code was also adapted from the upstream Gnome Shell source code.
*/
const GdkPixbuf = imports.gi.GdkPixbuf;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const GObject = imports.gi.GObject;
const Gtk = imports.gi.Gtk;
const Gdk = imports.gi.Gdk;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Me = imports.misc.extensionUtils.getCurrentExtension();
const Convenience = Me.imports.convenience;
const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']);
const _ = Gettext.gettext;
const N_ = function(e) { return e };
const Update = Me.imports.update;
const SCALE_UPDATE_TIMEOUT = 500;
const DEFAULT_PANEL_SIZES = [ 128, 96, 64, 48, 32, 24, 16 ];
const DEFAULT_FONT_SIZES = [ 96, 64, 48, 32, 24, 16, 0 ];
const DEFAULT_MARGIN_SIZES = [ 32, 24, 16, 12, 8, 4, 0 ];
const DEFAULT_PADDING_SIZES = [ 32, 24, 16, 12, 8, 4, 0, -1 ];
const MAX_WINDOW_INDICATOR = 4;
const SCHEMA_PATH = '/org/gnome/shell/extensions/dash-to-panel/';
const GSET = 'gnome-shell-extension-tool';
/**
* This function was copied from the activities-config extension
* https://github.com/nls1729/acme-code/tree/master/activities-config
* by Norman L. Smith.
*/
function cssHexString(css) {
let rrggbb = '#';
let start;
for (let loop = 0; loop < 3; loop++) {
let end = 0;
let xx = '';
for (let loop = 0; loop < 2; loop++) {
while (true) {
let x = css.slice(end, end + 1);
if ((x == '(') || (x == ',') || (x == ')'))
break;
end++;
}
if (loop == 0) {
end++;
start = end;
}
}
xx = parseInt(css.slice(start, end)).toString(16);
if (xx.length == 1)
xx = '0' + xx;
rrggbb += xx;
css = css.slice(end);
}
return rrggbb;
}
function setShortcut(settings, shortcutName) {
let shortcut_text = settings.get_string(shortcutName + '-text');
let [key, mods] = Gtk.accelerator_parse(shortcut_text);
if (Gtk.accelerator_valid(key, mods)) {
let shortcut = Gtk.accelerator_name(key, mods);
settings.set_strv(shortcutName, [shortcut]);
}
else {
settings.set_strv(shortcutName, []);
}
}
function checkHotkeyPrefix(settings) {
settings.delay();
let hotkeyPrefix = settings.get_string('hotkey-prefix-text');
if (hotkeyPrefix == 'Super')
hotkeyPrefix = '<Super>';
else if (hotkeyPrefix == 'SuperAlt')
hotkeyPrefix = '<Super><Alt>';
let [, mods] = Gtk.accelerator_parse(hotkeyPrefix);
let [, shift_mods] = Gtk.accelerator_parse('<Shift>' + hotkeyPrefix);
let [, ctrl_mods] = Gtk.accelerator_parse('<Ctrl>' + hotkeyPrefix);
let numHotkeys = 10;
for (let i = 1; i <= numHotkeys; i++) {
let number = i;
if (number == 10)
number = 0;
let key = Gdk.keyval_from_name(number.toString());
let key_kp = Gdk.keyval_from_name('KP_' + number.toString());
if (Gtk.accelerator_valid(key, mods)) {
let shortcut = Gtk.accelerator_name(key, mods);
let shortcut_kp = Gtk.accelerator_name(key_kp, mods);
// Setup shortcut strings
settings.set_strv('app-hotkey-' + i, [shortcut]);
settings.set_strv('app-hotkey-kp-' + i, [shortcut_kp]);
// With <Shift>
shortcut = Gtk.accelerator_name(key, shift_mods);
shortcut_kp = Gtk.accelerator_name(key_kp, shift_mods);
settings.set_strv('app-shift-hotkey-' + i, [shortcut]);
settings.set_strv('app-shift-hotkey-kp-' + i, [shortcut_kp]);
// With <Control>
shortcut = Gtk.accelerator_name(key, ctrl_mods);
shortcut_kp = Gtk.accelerator_name(key_kp, ctrl_mods);
settings.set_strv('app-ctrl-hotkey-' + i, [shortcut]);
settings.set_strv('app-ctrl-hotkey-kp-' + i, [shortcut_kp]);
}
else {
// Reset default settings for the relevant keys if the
// accelerators are invalid
let keys = ['app-hotkey-' + i, 'app-shift-hotkey-' + i, 'app-ctrl-hotkey-' + i, // Regular numbers
'app-hotkey-kp-' + i, 'app-shift-hotkey-kp-' + i, 'app-ctrl-hotkey-kp-' + i]; // Key-pad numbers
keys.forEach(function(val) {
settings.set_value(val, settings.get_default_value(val));
}, this);
}
}
settings.apply();
}
function mergeObjects(main, bck) {
for (var prop in bck) {
if (!main.hasOwnProperty(prop) && bck.hasOwnProperty(prop)) {
main[prop] = bck[prop];
}
}
return main;
};
const Settings = new Lang.Class({
Name: 'DashToPanel.Settings',
_init: function() {
this._settings = Convenience.getSettings('org.gnome.shell.extensions.dash-to-panel');
this._rtl = (Gtk.Widget.get_default_direction() == Gtk.TextDirection.RTL);
this._builder = new Gtk.Builder();
this._builder.set_translation_domain(Me.metadata['gettext-domain']);
this._builder.add_from_file(Me.path + '/Settings.ui');
this.notebook = this._builder.get_object('settings_notebook');
this.viewport = new Gtk.Viewport();
this.viewport.add(this.notebook);
this.widget = new Gtk.ScrolledWindow();
this.widget.add(this.viewport);
// Timeout to delay the update of the settings
this._panel_size_timeout = 0;
this._dot_height_timeout = 0;
this._tray_size_timeout = 0;
this._leftbox_size_timeout = 0;
this._appicon_margin_timeout = 0;
this._appicon_padding_timeout = 0;
this._opacity_timeout = 0;
this._tray_padding_timeout = 0;
this._statusicon_padding_timeout = 0;
this._leftbox_padding_timeout = 0;
this._bindSettings();
this._builder.connect_signals_full(Lang.bind(this, this._connector));
},
/**
* Connect signals
*/
_connector: function(builder, object, signal, handler) {
object.connect(signal, Lang.bind(this, this._SignalHandler[handler]));
},
_updateVerticalRelatedOptions: function() {
let position = this._settings.get_string('panel-position');
let isVertical = position == 'LEFT' || position == 'RIGHT';
let taskbarLocationCombo = this._builder.get_object('taskbar_position_combo');
let clockLocationCombo = this._builder.get_object('location_clock_combo');
let showDesktopWidthLabel = this._builder.get_object('show_showdesktop_width_label');
taskbarLocationCombo.remove_all();
clockLocationCombo.remove_all();
[
['LEFTPANEL', isVertical ? _('Top, with plugin icons collapsed to bottom') : _('Left, with plugin icons collapsed to right')],
['LEFTPANEL_FIXEDCENTER', isVertical ? _('Top, with fixed center plugin icons') : _('Left, with fixed center plugin icons')],
['LEFTPANEL_FLOATCENTER', isVertical ? _('Top, with floating center plugin icons') : _('Left, with floating center plugin icons')],
['CENTEREDMONITOR', _('Center, fixed in middle of monitor')],
['CENTEREDCONTENT', isVertical ? _('Center, floating between top and bottom elements') : _('Center, floating between left and right elements')]
].forEach(tl => taskbarLocationCombo.append.apply(taskbarLocationCombo, tl));
[
['BUTTONSLEFT', isVertical ? _('Top of plugin icons') : _('Left of plugin icons')],
['BUTTONSRIGHT', isVertical ? _('Bottom of plugin icons') : _('Right of plugin icons')],
['STATUSLEFT', isVertical ? _('Top of system indicators') : _('Left of system indicators')],
['STATUSRIGHT', isVertical ? _('Bottom of system indicators') : _('Right of system indicators')],
['TASKBARLEFT', isVertical ? _('Top of taskbar') : _('Left of taskbar')],
['TASKBARRIGHT', isVertical ? _('Bottom of taskbar') : _('Right of taskbar')]
].forEach(cl => clockLocationCombo.append.apply(clockLocationCombo, cl));
taskbarLocationCombo.set_active_id(this._settings.get_string('taskbar-position'));
clockLocationCombo.set_active_id(this._settings.get_string('location-clock'));
showDesktopWidthLabel.set_text(isVertical ? _('Show Desktop button height (px)') : _('Show Desktop button width (px)'));
},
_bindSettings: function() {
// Position and style panel
// Position option
let position = this._settings.get_string('panel-position');
switch (position) {
case 'BOTTOM':
this._builder.get_object('position_bottom_button').set_active(true);
break;
case 'TOP':
this._builder.get_object('position_top_button').set_active(true);
break;
case 'LEFT':
this._builder.get_object('position_left_button').set_active(true);
break;
case 'RIGHT':
this._builder.get_object('position_right_button').set_active(true);
break;
}
this._settings.connect('changed::panel-position', () => this._updateVerticalRelatedOptions());
this._updateVerticalRelatedOptions();
this._builder.get_object('location_clock_combo').connect('changed', Lang.bind (this, function(widget) {
let activeId = widget.get_active_id();
if (activeId) {
this._settings.set_string('location-clock', activeId);
}
}));
this._builder.get_object('taskbar_position_combo').connect('changed', Lang.bind (this, function(widget) {
let activeId = widget.get_active_id();
if (activeId) {
this._settings.set_string('taskbar-position', activeId);
}
}));
// size options
let panel_size_scale = this._builder.get_object('panel_size_scale');
panel_size_scale.set_range(DEFAULT_PANEL_SIZES[DEFAULT_PANEL_SIZES.length-1], DEFAULT_PANEL_SIZES[0]);
panel_size_scale.set_value(this._settings.get_int('panel-size'));
DEFAULT_PANEL_SIZES.slice(1, -1).forEach(function(val) {
panel_size_scale.add_mark(val, Gtk.PositionType.TOP, val.toString());
});
// Corrent for rtl languages
if (this._rtl) {
// Flip value position: this is not done automatically
panel_size_scale.set_value_pos(Gtk.PositionType.LEFT);
// I suppose due to a bug, having a more than one mark and one above a value of 100
// makes the rendering of the marks wrong in rtl. This doesn't happen setting the scale as not flippable
// and then manually inverting it
panel_size_scale.set_flippable(false);
panel_size_scale.set_inverted(true);
}
// Dots Position option
let dotPosition = this._settings.get_string('dot-position');
switch (dotPosition) {
case 'BOTTOM':
this._builder.get_object('dots_bottom_button').set_active(true);
break;
case 'TOP':
this._builder.get_object('dots_top_button').set_active(true);
break;
case 'LEFT':
this._builder.get_object('dots_left_button').set_active(true);
break;
case 'RIGHT':
this._builder.get_object('dots_right_button').set_active(true);
break;
}
this._builder.get_object('dot_style_focused_combo').set_active_id(this._settings.get_string('dot-style-focused'));
this._builder.get_object('dot_style_focused_combo').connect('changed', Lang.bind (this, function(widget) {
this._settings.set_string('dot-style-focused', widget.get_active_id());
}));
this._builder.get_object('dot_style_unfocused_combo').set_active_id(this._settings.get_string('dot-style-unfocused'));
this._builder.get_object('dot_style_unfocused_combo').connect('changed', Lang.bind (this, function(widget) {
this._settings.set_string('dot-style-unfocused', widget.get_active_id());
}));
for (let i = 1; i <= MAX_WINDOW_INDICATOR; i++) {
let idx = i;
this._builder.get_object('dot_color_' + idx + '_colorbutton').connect('notify::color', Lang.bind(this, function(button) {
let rgba = button.get_rgba();
let css = rgba.to_string();
let hexString = cssHexString(css);
this._settings.set_string('dot-color-' + idx, hexString);
}));
this._builder.get_object('dot_color_unfocused_' + idx + '_colorbutton').connect('notify::color', Lang.bind(this, function(button) {
let rgba = button.get_rgba();
let css = rgba.to_string();
let hexString = cssHexString(css);
this._settings.set_string('dot-color-unfocused-' + idx, hexString);
}));
}
this._builder.get_object('dot_color_apply_all_button').connect('clicked', Lang.bind(this, function() {
for (let i = 2; i <= MAX_WINDOW_INDICATOR; i++) {
this._settings.set_value('dot-color-' + i, this._settings.get_value('dot-color-1'));
let rgba = new Gdk.RGBA();
rgba.parse(this._settings.get_string('dot-color-' + i));
this._builder.get_object('dot_color_' + i + '_colorbutton').set_rgba(rgba);
}
}));
this._builder.get_object('dot_color_unfocused_apply_all_button').connect('clicked', Lang.bind(this, function() {
for (let i = 2; i <= MAX_WINDOW_INDICATOR; i++) {
this._settings.set_value('dot-color-unfocused-' + i, this._settings.get_value('dot-color-unfocused-1'));
let rgba = new Gdk.RGBA();
rgba.parse(this._settings.get_string('dot-color-unfocused-' + i));
this._builder.get_object('dot_color_unfocused_' + i + '_colorbutton').set_rgba(rgba);
}
}));
this._builder.get_object('focus_highlight_color_colorbutton').connect('notify::color', Lang.bind(this, function(button) {
let rgba = button.get_rgba();
let css = rgba.to_string();
let hexString = cssHexString(css);
this._settings.set_string('focus-highlight-color', hexString);
}));
this._builder.get_object('dot_style_options_button').connect('clicked', Lang.bind(this, function() {
let dialog = new Gtk.Dialog({ title: _('Running Indicator Options'),
transient_for: this.widget.get_toplevel(),
use_header_bar: true,
modal: true });
// GTK+ leaves positive values for application-defined response ids.
// Use +1 for the reset action
dialog.add_button(_('Reset to defaults'), 1);
let box = this._builder.get_object('box_dots_options');
dialog.get_content_area().add(box);
this._settings.bind('dot-color-dominant',
this._builder.get_object('dot_color_dominant_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('dot-color-override',
this._builder.get_object('dot_color_override_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
// when either becomes active, turn the other off
this._builder.get_object('dot_color_dominant_switch').connect('state-set', Lang.bind (this, function(widget) {
if (widget.get_active()) this._settings.set_boolean('dot-color-override', false);
}));
this._builder.get_object('dot_color_override_switch').connect('state-set', Lang.bind (this, function(widget) {
if (widget.get_active()) this._settings.set_boolean('dot-color-dominant', false);
}));
this._settings.bind('dot-color-unfocused-different',
this._builder.get_object('dot_color_unfocused_different_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('dot-color-override',
this._builder.get_object('grid_dot_color'),
'sensitive',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('dot-color-override',
this._builder.get_object('dot_color_unfocused_box'),
'sensitive',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('dot-color-unfocused-different',
this._builder.get_object('grid_dot_color_unfocused'),
'sensitive',
Gio.SettingsBindFlags.DEFAULT);
for (let i = 1; i <= MAX_WINDOW_INDICATOR; i++) {
let rgba = new Gdk.RGBA();
rgba.parse(this._settings.get_string('dot-color-' + i));
this._builder.get_object('dot_color_' + i + '_colorbutton').set_rgba(rgba);
rgba = new Gdk.RGBA();
rgba.parse(this._settings.get_string('dot-color-unfocused-' + i));
this._builder.get_object('dot_color_unfocused_' + i + '_colorbutton').set_rgba(rgba);
}
this._settings.bind('focus-highlight',
this._builder.get_object('focus_highlight_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('focus-highlight',
this._builder.get_object('grid_focus_highlight_options'),
'sensitive',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('focus-highlight-dominant',
this._builder.get_object('focus_highlight_dominant_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('focus-highlight-dominant',
this._builder.get_object('focus_highlight_color_label'),
'sensitive',
Gio.SettingsBindFlags.INVERT_BOOLEAN);
this._settings.bind('focus-highlight-dominant',
this._builder.get_object('focus_highlight_color_colorbutton'),
'sensitive',
Gio.SettingsBindFlags.INVERT_BOOLEAN);
(function() {
let rgba = new Gdk.RGBA();
rgba.parse(this._settings.get_string('focus-highlight-color'));
this._builder.get_object('focus_highlight_color_colorbutton').set_rgba(rgba);
}).apply(this);
this._builder.get_object('focus_highlight_opacity_spinbutton').set_value(this._settings.get_int('focus-highlight-opacity'));
this._builder.get_object('focus_highlight_opacity_spinbutton').connect('value-changed', Lang.bind (this, function(widget) {
this._settings.set_int('focus-highlight-opacity', widget.get_value());
}));
this._builder.get_object('dot_size_spinbutton').set_value(this._settings.get_int('dot-size'));
this._builder.get_object('dot_size_spinbutton').connect('value-changed', Lang.bind (this, function(widget) {
this._settings.set_int('dot-size', widget.get_value());
}));
dialog.connect('response', Lang.bind(this, function(dialog, id) {
if (id == 1) {
// restore default settings
this._settings.set_value('dot-color-dominant', this._settings.get_default_value('dot-color-dominant'));
this._settings.set_value('dot-color-override', this._settings.get_default_value('dot-color-override'));
this._settings.set_value('dot-color-unfocused-different', this._settings.get_default_value('dot-color-unfocused-different'));
this._settings.set_value('focus-highlight-color', this._settings.get_default_value('focus-highlight-color'));
let rgba = new Gdk.RGBA();
rgba.parse(this._settings.get_string('focus-highlight-color'));
this._builder.get_object('focus_highlight_color_colorbutton').set_rgba(rgba);
this._settings.set_value('focus-highlight-opacity', this._settings.get_default_value('focus-highlight-opacity'));
this._builder.get_object('focus_highlight_opacity_spinbutton').set_value(this._settings.get_int('focus-highlight-opacity'));
for (let i = 1; i <= MAX_WINDOW_INDICATOR; i++) {
this._settings.set_value('dot-color-' + i, this._settings.get_default_value('dot-color-' + i));
rgba = new Gdk.RGBA();
rgba.parse(this._settings.get_string('dot-color-' + i));
this._builder.get_object('dot_color_' + i + '_colorbutton').set_rgba(rgba);
this._settings.set_value('dot-color-unfocused-' + i, this._settings.get_default_value('dot-color-unfocused-' + i));
rgba = new Gdk.RGBA();
rgba.parse(this._settings.get_string('dot-color-unfocused-' + i));
this._builder.get_object('dot_color_unfocused_' + i + '_colorbutton').set_rgba(rgba);
}
this._settings.set_value('dot-size', this._settings.get_default_value('dot-size'));
this._builder.get_object('dot_size_spinbutton').set_value(this._settings.get_int('dot-size'));
this._settings.set_value('focus-highlight', this._settings.get_default_value('focus-highlight'));
this._settings.set_value('focus-highlight-dominant', this._settings.get_default_value('focus-highlight-dominant'));
} else {
// remove the settings box so it doesn't get destroyed;
dialog.get_content_area().remove(box);
dialog.destroy();
}
return;
}));
dialog.show_all();
}));
//multi-monitor
let monitors = [-1];
this._builder.get_object('multimon_primary_combo').append_text(_('Default (Primary monitor)'));
for (let i = 0, monitorNum = Gdk.Screen.get_default().get_n_monitors(); i < monitorNum; ++i) {
this._builder.get_object('multimon_primary_combo').append_text(_('Monitor ') + (i+1));
monitors.push(i);
}
this._builder.get_object('multimon_primary_combo').set_active(monitors.indexOf(this._settings.get_int('primary-monitor')));
this._builder.get_object('multimon_primary_combo').connect('changed', Lang.bind (this, function(widget) {
this._settings.set_int('primary-monitor', monitors[widget.get_active()]);
}));
this._settings.bind('multi-monitors',
this._builder.get_object('multimon_multi_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('multi-monitors',
this._builder.get_object('multimon_multi_options_button'),
'sensitive',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('isolate-monitors',
this._builder.get_object('multimon_multi_isolate_monitor_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('show-clock-all-monitors',
this._builder.get_object('multimon_multi_show_clock_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('show-status-menu-all-monitors',
this._builder.get_object('multimon_multi_show_status_menu_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('show-favorites-all-monitors',
this._builder.get_object('multimon_multi_show_favorites_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
if (monitors.length === 1) {
this._builder.get_object('multimon_listbox').set_sensitive(false);
this._builder.get_object('multimon_multi_switch').set_active(false);
}
this._builder.get_object('multimon_multi_options_button').connect('clicked', Lang.bind(this, function() {
let dialog = new Gtk.Dialog({ title: _('Multi-monitors options'),
transient_for: this.widget.get_toplevel(),
use_header_bar: true,
modal: true });
// GTK+ leaves positive values for application-defined response ids.
// Use +1 for the reset action
dialog.add_button(_('Reset to defaults'), 1);
let box = this._builder.get_object('box_multimon_multi_options');
dialog.get_content_area().add(box);
dialog.connect('response', Lang.bind(this, function(dialog, id) {
if (id == 1) {
// restore default settings
this._settings.set_value('isolate-monitors', this._settings.get_default_value('isolate-monitors'));
this._settings.set_value('show-favorites-all-monitors', this._settings.get_default_value('show-favorites-all-monitors'));
this._settings.set_value('show-clock-all-monitors', this._settings.get_default_value('show-clock-all-monitors'));
this._settings.set_value('show-status-menu-all-monitors', this._settings.get_default_value('show-status-menu-all-monitors'));
} else {
// remove the settings box so it doesn't get destroyed;
dialog.get_content_area().remove(box);
dialog.destroy();
}
return;
}));
dialog.show_all();
}));
//dynamic opacity
this._settings.bind('trans-use-custom-bg',
this._builder.get_object('trans_bg_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('trans-use-custom-bg',
this._builder.get_object('trans_bg_color_colorbutton'),
'sensitive',
Gio.SettingsBindFlags.DEFAULT);
let rgba = new Gdk.RGBA();
rgba.parse(this._settings.get_string('trans-bg-color'));
this._builder.get_object('trans_bg_color_colorbutton').set_rgba(rgba);
this._builder.get_object('trans_bg_color_colorbutton').connect('notify::color', Lang.bind(this, function (button) {
let rgba = button.get_rgba();
let css = rgba.to_string();
let hexString = cssHexString(css);
this._settings.set_string('trans-bg-color', hexString);
}));
this._settings.bind('trans-use-custom-opacity',
this._builder.get_object('trans_opacity_override_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('trans-use-custom-opacity',
this._builder.get_object('trans_opacity_box'),
'sensitive',
Gio.SettingsBindFlags.DEFAULT);
this._builder.get_object('trans_opacity_override_switch').connect('notify::active', (widget) => {
if (!widget.get_active())
this._builder.get_object('trans_dyn_switch').set_active(false);
});
this._builder.get_object('trans_opacity_spinbutton').set_value(this._settings.get_double('trans-panel-opacity') * 100);
this._builder.get_object('trans_opacity_spinbutton').connect('value-changed', Lang.bind(this, function (widget) {
this._settings.set_double('trans-panel-opacity', widget.get_value() * 0.01);
}));
this._settings.bind('trans-use-dynamic-opacity',
this._builder.get_object('trans_dyn_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('trans-use-dynamic-opacity',
this._builder.get_object('trans_dyn_options_button'),
'sensitive',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('trans-dynamic-behavior',
this._builder.get_object('trans_options_window_type_combo'),
'active-id',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('trans-use-custom-gradient',
this._builder.get_object('trans_gradient_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('trans-use-custom-gradient',
this._builder.get_object('trans_gradient_box'),
'sensitive',
Gio.SettingsBindFlags.DEFAULT);
rgba.parse(this._settings.get_string('trans-gradient-top-color'));
this._builder.get_object('trans_gradient_color1_colorbutton').set_rgba(rgba);
this._builder.get_object('trans_gradient_color1_colorbutton').connect('notify::color', Lang.bind(this, function (button) {
let rgba = button.get_rgba();
let css = rgba.to_string();
let hexString = cssHexString(css);
this._settings.set_string('trans-gradient-top-color', hexString);
}));
this._builder.get_object('trans_gradient_color1_spinbutton').set_value(this._settings.get_double('trans-gradient-top-opacity') * 100);
this._builder.get_object('trans_gradient_color1_spinbutton').connect('value-changed', Lang.bind(this, function (widget) {
this._settings.set_double('trans-gradient-top-opacity', widget.get_value() * 0.01);
}));
rgba.parse(this._settings.get_string('trans-gradient-bottom-color'));
this._builder.get_object('trans_gradient_color2_colorbutton').set_rgba(rgba);
this._builder.get_object('trans_gradient_color2_colorbutton').connect('notify::color', Lang.bind(this, function (button) {
let rgba = button.get_rgba();
let css = rgba.to_string();
let hexString = cssHexString(css);
this._settings.set_string('trans-gradient-bottom-color', hexString);
}));
this._builder.get_object('trans_gradient_color2_spinbutton').set_value(this._settings.get_double('trans-gradient-bottom-opacity') * 100);
this._builder.get_object('trans_gradient_color2_spinbutton').connect('value-changed', Lang.bind(this, function (widget) {
this._settings.set_double('trans-gradient-bottom-opacity', widget.get_value() * 0.01);
}));
this._builder.get_object('trans_options_distance_spinbutton').set_value(this._settings.get_int('trans-dynamic-distance'));
this._builder.get_object('trans_options_distance_spinbutton').connect('value-changed', Lang.bind(this, function (widget) {
this._settings.set_int('trans-dynamic-distance', widget.get_value());
}));
this._builder.get_object('trans_options_min_opacity_spinbutton').set_value(this._settings.get_double('trans-dynamic-anim-target') * 100);
this._builder.get_object('trans_options_min_opacity_spinbutton').connect('value-changed', Lang.bind(this, function (widget) {
this._settings.set_double('trans-dynamic-anim-target', widget.get_value() * 0.01);
}));
this._builder.get_object('trans_options_anim_time_spinbutton').set_value(this._settings.get_int('trans-dynamic-anim-time'));
this._builder.get_object('trans_options_anim_time_spinbutton').connect('value-changed', Lang.bind(this, function (widget) {
this._settings.set_int('trans-dynamic-anim-time', widget.get_value());
}));
this._builder.get_object('trans_dyn_options_button').connect('clicked', Lang.bind(this, function() {
let dialog = new Gtk.Dialog({ title: _('Dynamic opacity options'),
transient_for: this.widget.get_toplevel(),
use_header_bar: true,
modal: true });
// GTK+ leaves positive values for application-defined response ids.
// Use +1 for the reset action
dialog.add_button(_('Reset to defaults'), 1);
let box = this._builder.get_object('box_dynamic_opacity_options');
dialog.get_content_area().add(box);
dialog.connect('response', Lang.bind(this, function(dialog, id) {
if (id == 1) {
// restore default settings
this._settings.set_value('trans-dynamic-behavior', this._settings.get_default_value('trans-dynamic-behavior'));
this._settings.set_value('trans-dynamic-distance', this._settings.get_default_value('trans-dynamic-distance'));
this._builder.get_object('trans_options_distance_spinbutton').set_value(this._settings.get_int('trans-dynamic-distance'));
this._settings.set_value('trans-dynamic-anim-target', this._settings.get_default_value('trans-dynamic-anim-target'));
this._builder.get_object('trans_options_min_opacity_spinbutton').set_value(this._settings.get_double('trans-dynamic-anim-target') * 100);
this._settings.set_value('trans-dynamic-anim-time', this._settings.get_default_value('trans-dynamic-anim-time'));
this._builder.get_object('trans_options_anim_time_spinbutton').set_value(this._settings.get_int('trans-dynamic-anim-time'));
} else {
// remove the settings box so it doesn't get destroyed;
dialog.get_content_area().remove(box);
dialog.destroy();
}
return;
}));
dialog.show_all();
}));
this._settings.bind('intellihide',
this._builder.get_object('intellihide_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('intellihide',
this._builder.get_object('intellihide_options_button'),
'sensitive',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('intellihide-hide-from-windows',
this._builder.get_object('intellihide_window_hide_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('intellihide-hide-from-windows',
this._builder.get_object('intellihide_behaviour_options'),
'sensitive',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('intellihide-behaviour',
this._builder.get_object('intellihide_behaviour_combo'),
'active-id',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('intellihide-use-pressure',
this._builder.get_object('intellihide_use_pressure_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('intellihide-use-pressure',
this._builder.get_object('intellihide_use_pressure_options'),
'sensitive',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('intellihide-show-in-fullscreen',
this._builder.get_object('intellihide_show_in_fullscreen_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('intellihide-only-secondary',
this._builder.get_object('intellihide_only_secondary_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('multi-monitors',
this._builder.get_object('grid_intellihide_only_secondary'),
'sensitive',
Gio.SettingsBindFlags.DEFAULT);
this._builder.get_object('multimon_multi_switch').connect('notify::active', (widget) => {
if (!widget.get_active())
this._builder.get_object('intellihide_only_secondary_switch').set_active(false);
});
this._builder.get_object('intellihide_pressure_threshold_spinbutton').set_value(this._settings.get_int('intellihide-pressure-threshold'));
this._builder.get_object('intellihide_pressure_threshold_spinbutton').connect('value-changed', Lang.bind(this, function (widget) {
this._settings.set_int('intellihide-pressure-threshold', widget.get_value());
}));
this._builder.get_object('intellihide_pressure_time_spinbutton').set_value(this._settings.get_int('intellihide-pressure-time'));
this._builder.get_object('intellihide_pressure_time_spinbutton').connect('value-changed', Lang.bind(this, function (widget) {
this._settings.set_int('intellihide-pressure-time', widget.get_value());
}));
this._settings.bind('intellihide-key-toggle-text',
this._builder.get_object('intellihide_toggle_entry'),
'text',
Gio.SettingsBindFlags.DEFAULT);
this._settings.connect('changed::intellihide-key-toggle-text', () => setShortcut(this._settings, 'intellihide-key-toggle'));
this._builder.get_object('intellihide_animation_time_spinbutton').set_value(this._settings.get_int('intellihide-animation-time'));
this._builder.get_object('intellihide_animation_time_spinbutton').connect('value-changed', Lang.bind (this, function(widget) {
this._settings.set_int('intellihide-animation-time', widget.get_value());
}));
this._builder.get_object('intellihide_close_delay_spinbutton').set_value(this._settings.get_int('intellihide-close-delay'));
this._builder.get_object('intellihide_close_delay_spinbutton').connect('value-changed', Lang.bind (this, function(widget) {
this._settings.set_int('intellihide-close-delay', widget.get_value());
}));
this._builder.get_object('intellihide_enable_start_delay_spinbutton').set_value(this._settings.get_int('intellihide-enable-start-delay'));
this._builder.get_object('intellihide_enable_start_delay_spinbutton').connect('value-changed', Lang.bind (this, function(widget) {
this._settings.set_int('intellihide-enable-start-delay', widget.get_value());
}));
this._builder.get_object('intellihide_options_button').connect('clicked', Lang.bind(this, function() {
let dialog = new Gtk.Dialog({ title: _('Intellihide options'),
transient_for: this.widget.get_toplevel(),
use_header_bar: true,
modal: true });
// GTK+ leaves positive values for application-defined response ids.
// Use +1 for the reset action
dialog.add_button(_('Reset to defaults'), 1);
let box = this._builder.get_object('box_intellihide_options');
dialog.get_content_area().add(box);
dialog.connect('response', Lang.bind(this, function(dialog, id) {
if (id == 1) {
// restore default settings
this._settings.set_value('intellihide-hide-from-windows', this._settings.get_default_value('intellihide-hide-from-windows'));
this._settings.set_value('intellihide-behaviour', this._settings.get_default_value('intellihide-behaviour'));
this._settings.set_value('intellihide-use-pressure', this._settings.get_default_value('intellihide-use-pressure'));
this._settings.set_value('intellihide-show-in-fullscreen', this._settings.get_default_value('intellihide-show-in-fullscreen'));
this._settings.set_value('intellihide-only-secondary', this._settings.get_default_value('intellihide-only-secondary'));
this._settings.set_value('intellihide-pressure-threshold', this._settings.get_default_value('intellihide-pressure-threshold'));
this._builder.get_object('intellihide_pressure_threshold_spinbutton').set_value(this._settings.get_int('intellihide-pressure-threshold'));
this._settings.set_value('intellihide-pressure-time', this._settings.get_default_value('intellihide-pressure-time'));
this._builder.get_object('intellihide_pressure_time_spinbutton').set_value(this._settings.get_int('intellihide-pressure-time'));
this._settings.set_value('intellihide-key-toggle-text', this._settings.get_default_value('intellihide-key-toggle-text'));
this._settings.set_value('intellihide-animation-time', this._settings.get_default_value('intellihide-animation-time'));
this._builder.get_object('intellihide_animation_time_spinbutton').set_value(this._settings.get_int('intellihide-animation-time'));
this._settings.set_value('intellihide-close-delay', this._settings.get_default_value('intellihide-close-delay'));
this._builder.get_object('intellihide_close_delay_spinbutton').set_value(this._settings.get_int('intellihide-close-delay'));
this._settings.set_value('intellihide-enable-start-delay', this._settings.get_default_value('intellihide-enable-start-delay'));
this._builder.get_object('intellihide_enable_start_delay_spinbutton').set_value(this._settings.get_int('intellihide-enable-start-delay'));
} else {
// remove the settings box so it doesn't get destroyed;
dialog.get_content_area().remove(box);
dialog.destroy();
}
return;
}));
dialog.show_all();
}));
// Behavior panel
this._settings.bind('show-show-apps-button',
this._builder.get_object('show_applications_button_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('show-show-apps-button',
this._builder.get_object('show_application_options_button'),
'sensitive',
Gio.SettingsBindFlags.DEFAULT);
this._builder.get_object('show_applications_side_padding_spinbutton').set_value(this._settings.get_int('show-apps-icon-side-padding'));
this._builder.get_object('show_applications_side_padding_spinbutton').connect('value-changed', Lang.bind (this, function(widget) {
this._settings.set_int('show-apps-icon-side-padding', widget.get_value());
}));
this._builder.get_object('show_application_options_button').connect('clicked', Lang.bind(this, function() {
let dialog = new Gtk.Dialog({ title: _('Show Applications options'),
transient_for: this.widget.get_toplevel(),
use_header_bar: true,
modal: true });
// GTK+ leaves positive values for application-defined response ids.
// Use +1 for the reset action
dialog.add_button(_('Reset to defaults'), 1);
let box = this._builder.get_object('show_applications_options');
dialog.get_content_area().add(box);
let fileChooser = this._builder.get_object('show_applications_icon_file_filebutton');
let fileImage = this._builder.get_object('show_applications_current_icon_image');
let fileFilter = new Gtk.FileFilter();
let handleIconChange = function(newIconPath) {
if (newIconPath && GLib.file_test(newIconPath, GLib.FileTest.EXISTS)) {
let file = Gio.File.new_for_path(newIconPath)
let pixbuf = GdkPixbuf.Pixbuf.new_from_stream_at_scale(file.read(null), 32, 32, true, null);
fileImage.set_from_pixbuf(pixbuf);
fileChooser.set_filename(newIconPath);
} else {
newIconPath = '';
fileImage.set_from_icon_name('view-app-grid-symbolic', 32);
fileChooser.unselect_all();
fileChooser.set_current_folder(GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_PICTURES));
}
this._settings.set_string('show-apps-icon-file', newIconPath || '');
};
fileFilter.add_pixbuf_formats();
fileChooser.filter = fileFilter;
fileChooser.connect('file-set', widget => handleIconChange.call(this, widget.get_filename()));
handleIconChange.call(this, this._settings.get_string('show-apps-icon-file'));
dialog.connect('response', Lang.bind(this, function(dialog, id) {
if (id == 1) {
// restore default settings
this._settings.set_value('show-apps-icon-side-padding', this._settings.get_default_value('show-apps-icon-side-padding'));
this._builder.get_object('show_applications_side_padding_spinbutton').set_value(this._settings.get_int('show-apps-icon-side-padding'));
handleIconChange.call(this, null);
} else {
// remove the settings box so it doesn't get destroyed;
dialog.get_content_area().remove(box);
dialog.destroy();
}
return;
}));
dialog.show_all();
}));
this._settings.bind('animate-show-apps',
this._builder.get_object('application_button_animation_button'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('show-show-apps-button',
this._builder.get_object('application_button_animation_button'),
'sensitive',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('show-activities-button',
this._builder.get_object('show_activities_button_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('show-showdesktop-button',
this._builder.get_object('show_showdesktop_button_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('show-showdesktop-button',
this._builder.get_object('show_showdesktop_options_button'),
'sensitive',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('show-showdesktop-hover',
this._builder.get_object('show_showdesktop_hide_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('show-showdesktop-hover',
this._builder.get_object('grid_show_showdesktop_hide_options'),
'sensitive',
Gio.SettingsBindFlags.DEFAULT);
this._builder.get_object('show_showdesktop_options_button').connect('clicked', Lang.bind(this, function() {
let dialog = new Gtk.Dialog({ title: _('Show Desktop options'),
transient_for: this.widget.get_toplevel(),
use_header_bar: true,
modal: true });
// GTK+ leaves positive values for application-defined response ids.
// Use +1 for the reset action
dialog.add_button(_('Reset to defaults'), 1);
let box = this._builder.get_object('box_show_showdesktop_options');
dialog.get_content_area().add(box);
this._builder.get_object('show_showdesktop_width_spinbutton').set_value(this._settings.get_int('showdesktop-button-width'));
this._builder.get_object('show_showdesktop_width_spinbutton').connect('value-changed', Lang.bind (this, function(widget) {
this._settings.set_int('showdesktop-button-width', widget.get_value());
}));
this._builder.get_object('show_showdesktop_delay_spinbutton').set_value(this._settings.get_int('show-showdesktop-delay'));
this._builder.get_object('show_showdesktop_delay_spinbutton').connect('value-changed', Lang.bind (this, function(widget) {
this._settings.set_int('show-showdesktop-delay', widget.get_value());
}));
this._builder.get_object('show_showdesktop_time_spinbutton').set_value(this._settings.get_int('show-showdesktop-time'));
this._builder.get_object('show_showdesktop_time_spinbutton').connect('value-changed', Lang.bind (this, function(widget) {
this._settings.set_int('show-showdesktop-time', widget.get_value());
}));
dialog.connect('response', Lang.bind(this, function(dialog, id) {
if (id == 1) {
// restore default settings
this._settings.set_value('showdesktop-button-width', this._settings.get_default_value('showdesktop-button-width'));
this._builder.get_object('show_showdesktop_width_spinbutton').set_value(this._settings.get_int('showdesktop-button-width'));
this._settings.set_value('show-showdesktop-hover', this._settings.get_default_value('show-showdesktop-hover'));
this._settings.set_value('show-showdesktop-delay', this._settings.get_default_value('show-showdesktop-delay'));
this._builder.get_object('show_showdesktop_delay_spinbutton').set_value(this._settings.get_int('show-showdesktop-delay'));
this._settings.set_value('show-showdesktop-time', this._settings.get_default_value('show-showdesktop-time'));
this._builder.get_object('show_showdesktop_time_spinbutton').set_value(this._settings.get_int('show-showdesktop-time'));
} else {
// remove the settings box so it doesn't get destroyed;
dialog.get_content_area().remove(box);
dialog.destroy();
}
return;
}));
dialog.show_all();
}));
this._settings.bind('show-appmenu',
this._builder.get_object('show_appmenu_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('show-window-previews',
this._builder.get_object('show_window_previews_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('show-window-previews',
this._builder.get_object('show_window_previews_button'),
'sensitive',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('show-tooltip',
this._builder.get_object('show_tooltip_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('show-favorites',
this._builder.get_object('show_favorite_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('show-running-apps',
this._builder.get_object('show_runnning_apps_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._setPreviewTitlePosition();
this._builder.get_object('grid_preview_title_font_color_colorbutton').connect('notify::color', Lang.bind(this, function (button) {
let rgba = button.get_rgba();
let css = rgba.to_string();
let hexString = cssHexString(css);
this._settings.set_string('window-preview-title-font-color', hexString);
}));
this._builder.get_object('show_window_previews_button').connect('clicked', Lang.bind(this, function() {
let dialog = new Gtk.Dialog({ title: _('Window preview options'),
transient_for: this.widget.get_toplevel(),
use_header_bar: true,
modal: true });
// GTK+ leaves positive values for application-defined response ids.
// Use +1 for the reset action
dialog.add_button(_('Reset to defaults'), 1);
let scrolledWindow = this._builder.get_object('box_window_preview_options');
adjustScrollableHeight(this._builder.get_object('viewport_window_preview_options'), scrolledWindow);
dialog.get_content_area().add(scrolledWindow);
this._builder.get_object('preview_timeout_spinbutton').set_value(this._settings.get_int('show-window-previews-timeout'));
this._builder.get_object('preview_timeout_spinbutton').connect('value-changed', Lang.bind (this, function(widget) {
this._settings.set_int('show-window-previews-timeout', widget.get_value());
}));
this._settings.bind('preview-middle-click-close',
this._builder.get_object('preview_middle_click_close_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('window-preview-fixed-x',
this._builder.get_object('preview_aspect_ratio_x_fixed_togglebutton'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('window-preview-fixed-y',
this._builder.get_object('preview_aspect_ratio_y_fixed_togglebutton'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('preview-use-custom-opacity',
this._builder.get_object('preview_custom_opacity_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('preview-use-custom-opacity',
this._builder.get_object('preview_custom_opacity_spinbutton'),
'sensitive',
Gio.SettingsBindFlags.DEFAULT);
this._builder.get_object('preview_custom_opacity_spinbutton').set_value(this._settings.get_int('preview-custom-opacity'));
this._builder.get_object('preview_custom_opacity_spinbutton').connect('value-changed', Lang.bind (this, function(widget) {
this._settings.set_int('preview-custom-opacity', widget.get_value());
}));
this._settings.bind('peek-mode',
this._builder.get_object('peek_mode_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('peek-mode',
this._builder.get_object('grid_enter_peek_mode_timeout'),
'sensitive',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('peek-mode',
this._builder.get_object('grid_peek_mode_opacity'),
'sensitive',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('window-preview-show-title',
this._builder.get_object('preview_show_title_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('window-preview-show-title',
this._builder.get_object('grid_preview_title_size'),
'sensitive',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('window-preview-show-title',
this._builder.get_object('grid_preview_title_weight'),
'sensitive',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('window-preview-show-title',
this._builder.get_object('grid_preview_title_font_color'),
'sensitive',
Gio.SettingsBindFlags.DEFAULT);
this._builder.get_object('enter_peek_mode_timeout_spinbutton').set_value(this._settings.get_int('enter-peek-mode-timeout'));
this._builder.get_object('enter_peek_mode_timeout_spinbutton').connect('value-changed', Lang.bind (this, function(widget) {
this._settings.set_int('enter-peek-mode-timeout', widget.get_value());
}));
this._builder.get_object('leave_timeout_spinbutton').set_value(this._settings.get_int('leave-timeout'));
this._builder.get_object('leave_timeout_spinbutton').connect('value-changed', Lang.bind (this, function(widget) {
this._settings.set_int('leave-timeout', widget.get_value());
}));
this._settings.bind('window-preview-hide-immediate-click',
this._builder.get_object('preview_immediate_click_button'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._builder.get_object('animation_time_spinbutton').set_value(this._settings.get_int('window-preview-animation-time'));
this._builder.get_object('animation_time_spinbutton').connect('value-changed', Lang.bind (this, function(widget) {
this._settings.set_int('window-preview-animation-time', widget.get_value());
}));
this._builder.get_object('peek_mode_opacity_spinbutton').set_value(this._settings.get_int('peek-mode-opacity'));
this._builder.get_object('peek_mode_opacity_spinbutton').connect('value-changed', Lang.bind (this, function(widget) {
this._settings.set_int('peek-mode-opacity', widget.get_value());
}));
this._builder.get_object('preview_size_spinbutton').set_value(this._settings.get_int('window-preview-size'));
this._builder.get_object('preview_size_spinbutton').connect('value-changed', Lang.bind (this, function(widget) {
this._settings.set_int('window-preview-size', widget.get_value());
}));
this._builder.get_object('preview_aspect_ratio_x_combo').set_active_id(this._settings.get_int('window-preview-aspect-ratio-x').toString());
this._builder.get_object('preview_aspect_ratio_x_combo').connect('changed', Lang.bind (this, function(widget) {
this._settings.set_int('window-preview-aspect-ratio-x', parseInt(widget.get_active_id(), 10));
}));
this._builder.get_object('preview_aspect_ratio_y_combo').set_active_id(this._settings.get_int('window-preview-aspect-ratio-y').toString());
this._builder.get_object('preview_aspect_ratio_y_combo').connect('changed', Lang.bind (this, function(widget) {
this._settings.set_int('window-preview-aspect-ratio-y', parseInt(widget.get_active_id(), 10));
}));
this._builder.get_object('preview_padding_spinbutton').set_value(this._settings.get_int('window-preview-padding'));
this._builder.get_object('preview_padding_spinbutton').connect('value-changed', Lang.bind (this, function(widget) {
this._settings.set_int('window-preview-padding', widget.get_value());
}));
this._builder.get_object('preview_title_size_spinbutton').set_value(this._settings.get_int('window-preview-title-font-size'));
this._builder.get_object('preview_title_size_spinbutton').connect('value-changed', Lang.bind (this, function(widget) {
this._settings.set_int('window-preview-title-font-size', widget.get_value());
}));
this._builder.get_object('grid_preview_title_weight_combo').set_active_id(this._settings.get_string('window-preview-title-font-weight'));
this._builder.get_object('grid_preview_title_weight_combo').connect('changed', Lang.bind (this, function(widget) {
this._settings.set_string('window-preview-title-font-weight', widget.get_active_id());
}));
(function() {
let rgba = new Gdk.RGBA();
rgba.parse(this._settings.get_string('window-preview-title-font-color'));
this._builder.get_object('grid_preview_title_font_color_colorbutton').set_rgba(rgba);
}).apply(this);
dialog.connect('response', Lang.bind(this, function(dialog, id) {
if (id == 1) {
// restore default settings
this._settings.set_value('show-window-previews-timeout', this._settings.get_default_value('show-window-previews-timeout'));
this._builder.get_object('preview_timeout_spinbutton').set_value(this._settings.get_int('show-window-previews-timeout'));
this._settings.set_value('leave-timeout', this._settings.get_default_value('leave-timeout'));
this._builder.get_object('leave_timeout_spinbutton').set_value(this._settings.get_int('leave-timeout'));
this._settings.set_value('window-preview-hide-immediate-click', this._settings.get_default_value('window-preview-hide-immediate-click'));
this._settings.set_value('window-preview-animation-time', this._settings.get_default_value('window-preview-animation-time'));
this._builder.get_object('animation_time_spinbutton').set_value(this._settings.get_int('window-preview-animation-time'));
this._settings.set_value('preview-use-custom-opacity', this._settings.get_default_value('preview-use-custom-opacity'));
this._settings.set_value('preview-custom-opacity', this._settings.get_default_value('preview-custom-opacity'));
this._builder.get_object('preview_custom_opacity_spinbutton').set_value(this._settings.get_int('preview-custom-opacity'));
this._settings.set_value('window-preview-title-position', this._settings.get_default_value('window-preview-title-position'));
this._setPreviewTitlePosition();
this._settings.set_value('peek-mode', this._settings.get_default_value('peek-mode'));
this._settings.set_value('window-preview-show-title', this._settings.get_default_value('window-preview-show-title'));
this._settings.set_value('enter-peek-mode-timeout', this._settings.get_default_value('enter-peek-mode-timeout'));
this._builder.get_object('enter_peek_mode_timeout_spinbutton').set_value(this._settings.get_int('enter-peek-mode-timeout'));
this._settings.set_value('peek-mode-opacity', this._settings.get_default_value('peek-mode-opacity'));
this._builder.get_object('peek_mode_opacity_spinbutton').set_value(this._settings.get_int('peek-mode-opacity'));
this._settings.set_value('window-preview-size', this._settings.get_default_value('window-preview-size'));
this._builder.get_object('preview_size_spinbutton').set_value(this._settings.get_int('window-preview-size'));
this._settings.set_value('window-preview-fixed-x', this._settings.get_default_value('window-preview-fixed-x'));
this._settings.set_value('window-preview-fixed-y', this._settings.get_default_value('window-preview-fixed-y'));
this._settings.set_value('window-preview-aspect-ratio-x', this._settings.get_default_value('window-preview-aspect-ratio-x'));
this._builder.get_object('preview_aspect_ratio_x_combo').set_active_id(this._settings.get_int('window-preview-aspect-ratio-x').toString());
this._settings.set_value('window-preview-aspect-ratio-y', this._settings.get_default_value('window-preview-aspect-ratio-y'));
this._builder.get_object('preview_aspect_ratio_y_combo').set_active_id(this._settings.get_int('window-preview-aspect-ratio-y').toString());
this._settings.set_value('window-preview-padding', this._settings.get_default_value('window-preview-padding'));
this._builder.get_object('preview_padding_spinbutton').set_value(this._settings.get_int('window-preview-padding'));
this._settings.set_value('preview-middle-click-close', this._settings.get_default_value('preview-middle-click-close'));
this._settings.set_value('window-preview-title-font-size', this._settings.get_default_value('window-preview-title-font-size'));
this._builder.get_object('preview_title_size_spinbutton').set_value(this._settings.get_int('window-preview-title-font-size'));
this._settings.set_value('window-preview-title-font-weight', this._settings.get_default_value('window-preview-title-font-weight'));
this._builder.get_object('grid_preview_title_weight_combo').set_active_id(this._settings.get_string('window-preview-title-font-weight'));
this._settings.set_value('window-preview-title-font-color', this._settings.get_default_value('window-preview-title-font-color'));
let rgba = new Gdk.RGBA();
rgba.parse(this._settings.get_string('window-preview-title-font-color'));
this._builder.get_object('grid_preview_title_font_color_colorbutton').set_rgba(rgba);
} else {
// remove the settings box so it doesn't get destroyed;
dialog.get_content_area().remove(scrolledWindow);
dialog.destroy();
}
return;
}));
dialog.show_all();
}));
this._settings.bind('isolate-workspaces',
this._builder.get_object('isolate_workspaces_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('group-apps',
this._builder.get_object('group_apps_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT | Gio.SettingsBindFlags.INVERT_BOOLEAN);
this._settings.bind('group-apps',
this._builder.get_object('show_group_apps_options_button'),
'sensitive',
Gio.SettingsBindFlags.DEFAULT | Gio.SettingsBindFlags.INVERT_BOOLEAN);
this._builder.get_object('group_apps_label_font_color_colorbutton').connect('notify::color', Lang.bind(this, function (button) {
let rgba = button.get_rgba();
let css = rgba.to_string();
let hexString = cssHexString(css);
this._settings.set_string('group-apps-label-font-color', hexString);
}));
this._settings.bind('group-apps-use-fixed-width',
this._builder.get_object('group_apps_use_fixed_width_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('group-apps-underline-unfocused',
this._builder.get_object('group_apps_underline_unfocused_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('group-apps-use-launchers',
this._builder.get_object('group_apps_use_launchers_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._builder.get_object('show_group_apps_options_button').connect('clicked', Lang.bind(this, function() {
let dialog = new Gtk.Dialog({ title: _('Ungrouped application options'),
transient_for: this.widget.get_toplevel(),
use_header_bar: true,
modal: true });
// GTK+ leaves positive values for application-defined response ids.
// Use +1 for the reset action
dialog.add_button(_('Reset to defaults'), 1);
let box = this._builder.get_object('box_group_apps_options');
dialog.get_content_area().add(box);
this._builder.get_object('group_apps_label_font_size_spinbutton').set_value(this._settings.get_int('group-apps-label-font-size'));
this._builder.get_object('group_apps_label_font_size_spinbutton').connect('value-changed', Lang.bind (this, function(widget) {
this._settings.set_int('group-apps-label-font-size', widget.get_value());
}));
this._builder.get_object('group_apps_label_font_weight_combo').set_active_id(this._settings.get_string('group-apps-label-font-weight'));
this._builder.get_object('group_apps_label_font_weight_combo').connect('changed', Lang.bind (this, function(widget) {
this._settings.set_string('group-apps-label-font-weight', widget.get_active_id());
}));
(function() {
let rgba = new Gdk.RGBA();
rgba.parse(this._settings.get_string('group-apps-label-font-color'));
this._builder.get_object('group_apps_label_font_color_colorbutton').set_rgba(rgba);
}).apply(this);
this._builder.get_object('group_apps_label_max_width_spinbutton').set_value(this._settings.get_int('group-apps-label-max-width'));
this._builder.get_object('group_apps_label_max_width_spinbutton').connect('value-changed', Lang.bind (this, function(widget) {
this._settings.set_int('group-apps-label-max-width', widget.get_value());
}));
dialog.connect('response', Lang.bind(this, function(dialog, id) {
if (id == 1) {
// restore default settings
this._settings.set_value('group-apps-label-font-size', this._settings.get_default_value('group-apps-label-font-size'));
this._builder.get_object('group_apps_label_font_size_spinbutton').set_value(this._settings.get_int('group-apps-label-font-size'));
this._settings.set_value('group-apps-label-font-weight', this._settings.get_default_value('group-apps-label-font-weight'));
this._builder.get_object('group_apps_label_font_weight_combo').set_active_id(this._settings.get_string('group-apps-label-font-weight'));
this._settings.set_value('group-apps-label-font-color', this._settings.get_default_value('group-apps-label-font-color'));
let rgba = new Gdk.RGBA();
rgba.parse(this._settings.get_string('group-apps-label-font-color'));
this._builder.get_object('group_apps_label_font_color_colorbutton').set_rgba(rgba);
this._settings.set_value('group-apps-label-max-width', this._settings.get_default_value('group-apps-label-max-width'));
this._builder.get_object('group_apps_label_max_width_spinbutton').set_value(this._settings.get_int('group-apps-label-max-width'));
this._settings.set_value('group-apps-use-fixed-width', this._settings.get_default_value('group-apps-use-fixed-width'));
this._settings.set_value('group-apps-underline-unfocused', this._settings.get_default_value('group-apps-underline-unfocused'));
this._settings.set_value('group-apps-use-launchers', this._settings.get_default_value('group-apps-use-launchers'));
} else {
// remove the settings box so it doesn't get destroyed;
dialog.get_content_area().remove(box);
dialog.destroy();
}
return;
}));
dialog.show_all();
}));
this._builder.get_object('click_action_combo').set_active_id(this._settings.get_string('click-action'));
this._builder.get_object('click_action_combo').connect('changed', Lang.bind (this, function(widget) {
this._settings.set_string('click-action', widget.get_active_id());
}));
this._builder.get_object('shift_click_action_combo').connect('changed', Lang.bind (this, function(widget) {
this._settings.set_string('shift-click-action', widget.get_active_id());
}));
this._builder.get_object('middle_click_action_combo').connect('changed', Lang.bind (this, function(widget) {
this._settings.set_string('middle-click-action', widget.get_active_id());
}));
this._builder.get_object('shift_middle_click_action_combo').connect('changed', Lang.bind (this, function(widget) {
this._settings.set_string('shift-middle-click-action', widget.get_active_id());
}));
// Create dialog for middle-click options
this._builder.get_object('middle_click_options_button').connect('clicked', Lang.bind(this, function() {
let dialog = new Gtk.Dialog({ title: _('Customize middle-click behavior'),
transient_for: this.widget.get_toplevel(),
use_header_bar: true,
modal: true });
// GTK+ leaves positive values for application-defined response ids.
// Use +1 for the reset action
dialog.add_button(_('Reset to defaults'), 1);
let box = this._builder.get_object('box_middle_click_options');
dialog.get_content_area().add(box);
this._builder.get_object('shift_click_action_combo').set_active_id(this._settings.get_string('shift-click-action'));
this._builder.get_object('middle_click_action_combo').set_active_id(this._settings.get_string('middle-click-action'));
this._builder.get_object('shift_middle_click_action_combo').set_active_id(this._settings.get_string('shift-middle-click-action'));
this._settings.bind('shift-click-action',
this._builder.get_object('shift_click_action_combo'),
'active-id',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('middle-click-action',
this._builder.get_object('middle_click_action_combo'),
'active-id',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('shift-middle-click-action',
this._builder.get_object('shift_middle_click_action_combo'),
'active-id',
Gio.SettingsBindFlags.DEFAULT);
dialog.connect('response', Lang.bind(this, function(dialog, id) {
if (id == 1) {
// restore default settings for the relevant keys
let keys = ['shift-click-action', 'middle-click-action', 'shift-middle-click-action'];
keys.forEach(function(val) {
this._settings.set_value(val, this._settings.get_default_value(val));
}, this);
this._builder.get_object('shift_click_action_combo').set_active_id(this._settings.get_string('shift-click-action'));
this._builder.get_object('middle_click_action_combo').set_active_id(this._settings.get_string('middle-click-action'));
this._builder.get_object('shift_middle_click_action_combo').set_active_id(this._settings.get_string('shift-middle-click-action'));
} else {
// remove the settings box so it doesn't get destroyed;
dialog.get_content_area().remove(box);
dialog.destroy();
}
return;
}));
dialog.show_all();
}));
this._builder.get_object('scroll_panel_combo').set_active_id(this._settings.get_string('scroll-panel-action'));
this._builder.get_object('scroll_panel_combo').connect('changed', Lang.bind (this, function(widget) {
this._settings.set_string('scroll-panel-action', widget.get_active_id());
}));
this._builder.get_object('scroll_icon_combo').set_active_id(this._settings.get_string('scroll-icon-action'));
this._builder.get_object('scroll_icon_combo').connect('changed', Lang.bind (this, function(widget) {
this._settings.set_string('scroll-icon-action', widget.get_active_id());
}));
// Create dialog for panel scroll options
this._builder.get_object('scroll_panel_options_button').connect('clicked', Lang.bind(this, function() {
let dialog = new Gtk.Dialog({ title: _('Customize panel scroll behavior'),
transient_for: this.widget.get_toplevel(),
use_header_bar: true,
modal: true });
// GTK+ leaves positive values for application-defined response ids.
// Use +1 for the reset action
dialog.add_button(_('Reset to defaults'), 1);
let box = this._builder.get_object('scroll_panel_options_box');
dialog.get_content_area().add(box);
this._builder.get_object('scroll_panel_options_delay_spinbutton').set_value(this._settings.get_int('scroll-panel-delay'));
this._builder.get_object('scroll_panel_options_delay_spinbutton').connect('value-changed', Lang.bind (this, function(widget) {
this._settings.set_int('scroll-panel-delay', widget.get_value());
}));
dialog.connect('response', Lang.bind(this, function(dialog, id) {
if (id == 1) {
// restore default settings
this._settings.set_value('scroll-panel-delay', this._settings.get_default_value('scroll-panel-delay'));
this._builder.get_object('scroll_panel_options_delay_spinbutton').set_value(this._settings.get_int('scroll-panel-delay'));
} else {
// remove the settings box so it doesn't get destroyed;
dialog.get_content_area().remove(box);
dialog.destroy();
}
return;
}));
dialog.show_all();
}));
// Create dialog for icon scroll options
this._builder.get_object('scroll_icon_options_button').connect('clicked', Lang.bind(this, function() {
let dialog = new Gtk.Dialog({ title: _('Customize icon scroll behavior'),
transient_for: this.widget.get_toplevel(),
use_header_bar: true,
modal: true });
// GTK+ leaves positive values for application-defined response ids.
// Use +1 for the reset action
dialog.add_button(_('Reset to defaults'), 1);
let box = this._builder.get_object('scroll_icon_options_box');
dialog.get_content_area().add(box);
this._builder.get_object('scroll_icon_options_delay_spinbutton').set_value(this._settings.get_int('scroll-icon-delay'));
this._builder.get_object('scroll_icon_options_delay_spinbutton').connect('value-changed', Lang.bind (this, function(widget) {
this._settings.set_int('scroll-icon-delay', widget.get_value());
}));
dialog.connect('response', Lang.bind(this, function(dialog, id) {
if (id == 1) {
// restore default settings
this._settings.set_value('scroll-icon-delay', this._settings.get_default_value('scroll-icon-delay'));
this._builder.get_object('scroll_icon_options_delay_spinbutton').set_value(this._settings.get_int('scroll-icon-delay'));
} else {
// remove the settings box so it doesn't get destroyed;
dialog.get_content_area().remove(box);
dialog.destroy();
}
return;
}));
dialog.show_all();
}));
this._settings.bind('hot-keys',
this._builder.get_object('hot_keys_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('hot-keys',
this._builder.get_object('overlay_button'),
'sensitive',
Gio.SettingsBindFlags.DEFAULT);
this._builder.get_object('overlay_combo').connect('changed', Lang.bind (this, function(widget) {
this._settings.set_string('hotkeys-overlay-combo', widget.get_active_id());
}));
this._settings.bind('shortcut-previews',
this._builder.get_object('shortcut_preview_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._builder.get_object('shortcut_num_keys_combo').set_active_id(this._settings.get_string('shortcut-num-keys'));
this._builder.get_object('shortcut_num_keys_combo').connect('changed', Lang.bind (this, function(widget) {
this._settings.set_string('shortcut-num-keys', widget.get_active_id());
}));
this._settings.connect('changed::hotkey-prefix-text', Lang.bind(this, function() {checkHotkeyPrefix(this._settings);}));
this._builder.get_object('hotkey_prefix_combo').set_active_id(this._settings.get_string('hotkey-prefix-text'));
this._settings.bind('hotkey-prefix-text',
this._builder.get_object('hotkey_prefix_combo'),
'active-id',
Gio.SettingsBindFlags.DEFAULT);
this._builder.get_object('overlay_combo').set_active_id(this._settings.get_string('hotkeys-overlay-combo'));
this._settings.bind('hotkeys-overlay-combo',
this._builder.get_object('overlay_combo'),
'active-id',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('overlay-timeout',
this._builder.get_object('timeout_spinbutton'),
'value',
Gio.SettingsBindFlags.DEFAULT);
if (this._settings.get_string('hotkeys-overlay-combo') !== 'TEMPORARILY') {
this._builder.get_object('timeout_spinbutton').set_sensitive(false);
}
this._settings.connect('changed::hotkeys-overlay-combo', Lang.bind(this, function() {
if (this._settings.get_string('hotkeys-overlay-combo') !== 'TEMPORARILY')
this._builder.get_object('timeout_spinbutton').set_sensitive(false);
else
this._builder.get_object('timeout_spinbutton').set_sensitive(true);
}));
this._settings.bind('shortcut-text',
this._builder.get_object('shortcut_entry'),
'text',
Gio.SettingsBindFlags.DEFAULT);
this._settings.connect('changed::shortcut-text', Lang.bind(this, function() {setShortcut(this._settings, 'shortcut');}));
// Create dialog for number overlay options
this._builder.get_object('overlay_button').connect('clicked', Lang.bind(this, function() {
let dialog = new Gtk.Dialog({ title: _('Advanced hotkeys options'),
transient_for: this.widget.get_toplevel(),
use_header_bar: true,
modal: true });
// GTK+ leaves positive values for application-defined response ids.
// Use +1 for the reset action
dialog.add_button(_('Reset to defaults'), 1);
let box = this._builder.get_object('box_overlay_shortcut');
dialog.get_content_area().add(box);
dialog.connect('response', Lang.bind(this, function(dialog, id) {
if (id == 1) {
// restore default settings for the relevant keys
let keys = ['hotkey-prefix-text', 'shortcut-text', 'hotkeys-overlay-combo', 'overlay-timeout', 'shortcut-previews'];
keys.forEach(function(val) {
this._settings.set_value(val, this._settings.get_default_value(val));
}, this);
} else {
// remove the settings box so it doesn't get destroyed;
dialog.get_content_area().remove(box);
dialog.destroy();
}
return;
}));
dialog.show_all();
}));
// setup dialog for secondary menu options
this._builder.get_object('secondarymenu_options_button').connect('clicked', Lang.bind(this, function() {
let dialog = new Gtk.Dialog({ title: _('Secondary Menu Options'),
transient_for: this.widget.get_toplevel(),
use_header_bar: true,
modal: true });
// GTK+ leaves positive values for application-defined response ids.
// Use +1 for the reset action
dialog.add_button(_('Reset to defaults'), 1);
let box = this._builder.get_object('box_secondarymenu_options');
dialog.get_content_area().add(box);
this._settings.bind('secondarymenu-contains-appmenu',
this._builder.get_object('secondarymenu_appmenu_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('secondarymenu-contains-showdetails',
this._builder.get_object('secondarymenu_showdetails_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
dialog.connect('response', Lang.bind(this, function(dialog, id) {
if (id == 1) {
// restore default settings
this._settings.set_value('secondarymenu-contains-appmenu', this._settings.get_default_value('secondarymenu-contains-appmenu'));
this._settings.set_value('secondarymenu-contains-showdetails', this._settings.get_default_value('secondarymenu-contains-showdetails'));
} else {
// remove the settings box so it doesn't get destroyed;
dialog.get_content_area().remove(box);
dialog.destroy();
}
return;
}));
dialog.show_all();
}));
// setup dialog for advanced options
this._builder.get_object('button_advanced_options').connect('clicked', Lang.bind(this, function() {
let dialog = new Gtk.Dialog({ title: _('Advanced Options'),
transient_for: this.widget.get_toplevel(),
use_header_bar: true,
modal: true });
// GTK+ leaves positive values for application-defined response ids.
// Use +1 for the reset action
dialog.add_button(_('Reset to defaults'), 1);
let box = this._builder.get_object('box_advanced_options');
dialog.get_content_area().add(box);
dialog.connect('response', Lang.bind(this, function(dialog, id) {
if (id == 1) {
// restore default settings
} else {
// remove the settings box so it doesn't get destroyed;
dialog.get_content_area().remove(box);
dialog.destroy();
}
return;
}));
dialog.show_all();
}));
// Fine-tune panel
let sizeScales = [
{objectName: 'tray_size_scale', valueName: 'tray-size', range: DEFAULT_FONT_SIZES },
{objectName: 'leftbox_size_scale', valueName: 'leftbox-size', range: DEFAULT_FONT_SIZES },
{objectName: 'appicon_margin_scale', valueName: 'appicon-margin', range: DEFAULT_MARGIN_SIZES },
{objectName: 'appicon_padding_scale', valueName: 'appicon-padding', range: DEFAULT_MARGIN_SIZES },
{objectName: 'tray_padding_scale', valueName: 'tray-padding', range: DEFAULT_PADDING_SIZES },
{objectName: 'leftbox_padding_scale', valueName: 'leftbox-padding', range: DEFAULT_PADDING_SIZES },
{objectName: 'statusicon_padding_scale', valueName: 'status-icon-padding', range: DEFAULT_PADDING_SIZES }
];
for(var idx in sizeScales) {
let size_scale = this._builder.get_object(sizeScales[idx].objectName);
let range = sizeScales[idx].range;
size_scale.set_range(range[range.length-1], range[0]);
size_scale.set_value(this._settings.get_int(sizeScales[idx].valueName));
range.slice(1, -1).forEach(function(val) {
size_scale.add_mark(val, Gtk.PositionType.TOP, val.toString());
});
// Corrent for rtl languages
if (this._rtl) {
// Flip value position: this is not done automatically
size_scale.set_value_pos(Gtk.PositionType.LEFT);
// I suppose due to a bug, having a more than one mark and one above a value of 100
// makes the rendering of the marks wrong in rtl. This doesn't happen setting the scale as not flippable
// and then manually inverting it
size_scale.set_flippable(false);
size_scale.set_inverted(true);
}
}
this._settings.bind('animate-app-switch',
this._builder.get_object('animate_app_switch_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('animate-window-launch',
this._builder.get_object('animate_window_launch_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('stockgs-keep-dash',
this._builder.get_object('stockgs_dash_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
this._settings.bind('stockgs-panelbtn-click-only',
this._builder.get_object('stockgs_panelbtn_switch'),
'active',
Gio.SettingsBindFlags.DEFAULT);
// About Panel
this._builder.get_object('extension_version').set_label(Me.metadata.version.toString() + (Me.metadata.commit ? ' (' + Me.metadata.commit + ')' : ''));
this._builder.get_object('importexport_export_button').connect('clicked', widget => {
this._showFileChooser(
_('Export settings'),
{ action: Gtk.FileChooserAction.SAVE,
do_overwrite_confirmation: true },
Gtk.STOCK_SAVE,
filename => {
let file = Gio.file_new_for_path(filename);
let raw = file.replace(null, false, Gio.FileCreateFlags.NONE, null);
let out = Gio.BufferedOutputStream.new_sized(raw, 4096);
out.write_all(GLib.spawn_command_line_sync('dconf dump ' + SCHEMA_PATH)[1], null);
out.close(null);
}
);
});
this._builder.get_object('importexport_import_button').connect('clicked', widget => {
this._showFileChooser(
_('Import settings'),
{ action: Gtk.FileChooserAction.OPEN },
Gtk.STOCK_OPEN,
filename => {
let settingsFile = Gio.File.new_for_path(filename);
let [ , pid, stdin, stdout, stderr] =
GLib.spawn_async_with_pipes(
null,
['dconf', 'load', SCHEMA_PATH],
null,
GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD,
null
);
stdin = new Gio.UnixOutputStream({ fd: stdin, close_fd: true });
GLib.close(stdout);
GLib.close(stderr);
let [ , , , retCode] = GLib.spawn_command_line_sync(GSET + ' -d ' + Me.uuid);
if (retCode == 0) {
GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, () => GLib.spawn_command_line_sync(GSET + ' -e ' + Me.uuid));
}
stdin.splice(settingsFile.read(null), Gio.OutputStreamSpliceFlags.CLOSE_SOURCE | Gio.OutputStreamSpliceFlags.CLOSE_TARGET, null);
}
);
});
let updateCheckSwitch = this._builder.get_object('updates_check_switch');
updateCheckSwitch.set_sensitive(false);
this._builder.get_object('updates_check_now_button').connect('clicked', widget => {
this._settings.set_boolean('force-check-update', true);
});
},
_setPreviewTitlePosition: function() {
switch (this._settings.get_string('window-preview-title-position')) {
case 'BOTTOM':
this._builder.get_object('preview_title_position_bottom_button').set_active(true);
break;
case 'TOP':
this._builder.get_object('preview_title_position_top_button').set_active(true);
break;
}
},
_showFileChooser: function(title, params, acceptBtn, acceptHandler) {
let dialog = new Gtk.FileChooserDialog(mergeObjects({ title: title, transient_for: this.widget.get_toplevel() }, params));
dialog.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL);
dialog.add_button(acceptBtn, Gtk.ResponseType.ACCEPT);
if (dialog.run() == Gtk.ResponseType.ACCEPT) {
try {
acceptHandler(dialog.get_filename());
} catch(e) {
log('error from dash-to-panel filechooser: ' + e);
}
}
dialog.destroy();
},
/**
* Object containing all signals defined in the glade file
*/
_SignalHandler: {
position_bottom_button_toggled_cb: function(button) {
if (button.get_active())
this._settings.set_string('panel-position', "BOTTOM");
},
position_top_button_toggled_cb: function(button) {
if (button.get_active())
this._settings.set_string('panel-position', "TOP");
},
position_left_button_toggled_cb: function(button) {
if (button.get_active())
this._settings.set_string('panel-position', "LEFT");
},
position_right_button_toggled_cb: function(button) {
if (button.get_active())
this._settings.set_string('panel-position', "RIGHT");
},
dots_bottom_button_toggled_cb: function(button) {
if (button.get_active())
this._settings.set_string('dot-position', "BOTTOM");
},
dots_top_button_toggled_cb: function(button) {
if (button.get_active())
this._settings.set_string('dot-position', "TOP");
},
dots_left_button_toggled_cb: function(button) {
if (button.get_active())
this._settings.set_string('dot-position', "LEFT");
},
dots_right_button_toggled_cb: function(button) {
if (button.get_active())
this._settings.set_string('dot-position', "RIGHT");
},
preview_title_position_bottom_button_toggled_cb: function(button) {
if (button.get_active())
this._settings.set_string('window-preview-title-position', 'BOTTOM');
},
preview_title_position_top_button_toggled_cb: function(button) {
if (button.get_active())
this._settings.set_string('window-preview-title-position', 'TOP');
},
panel_size_scale_format_value_cb: function(scale, value) {
return value+ ' px';
},
panel_size_scale_value_changed_cb: function(scale) {
// Avoid settings the size consinuosly
if (this._panel_size_timeout > 0)
Mainloop.source_remove(this._panel_size_timeout);
this._panel_size_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() {
this._settings.set_int('panel-size', scale.get_value());
this._panel_size_timeout = 0;
return GLib.SOURCE_REMOVE;
}));
},
tray_size_scale_format_value_cb: function(scale, value) {
return value+ ' px';
},
tray_size_scale_value_changed_cb: function(scale) {
// Avoid settings the size consinuosly
if (this._tray_size_timeout > 0)
Mainloop.source_remove(this._tray_size_timeout);
this._tray_size_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() {
this._settings.set_int('tray-size', scale.get_value());
this._tray_size_timeout = 0;
return GLib.SOURCE_REMOVE;
}));
},
leftbox_size_scale_format_value_cb: function(scale, value) {
return value+ ' px';
},
leftbox_size_scale_value_changed_cb: function(scale) {
// Avoid settings the size consinuosly
if (this._leftbox_size_timeout > 0)
Mainloop.source_remove(this._leftbox_size_timeout);
this._leftbox_size_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() {
this._settings.set_int('leftbox-size', scale.get_value());
this._leftbox_size_timeout = 0;
return GLib.SOURCE_REMOVE;
}));
},
appicon_margin_scale_format_value_cb: function(scale, value) {
return value+ ' px';
},
appicon_margin_scale_value_changed_cb: function(scale) {
// Avoid settings the size consinuosly
if (this._appicon_margin_timeout > 0)
Mainloop.source_remove(this._appicon_margin_timeout);
this._appicon_margin_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() {
this._settings.set_int('appicon-margin', scale.get_value());
this._appicon_margin_timeout = 0;
return GLib.SOURCE_REMOVE;
}));
},
appicon_padding_scale_format_value_cb: function(scale, value) {
return value + ' px';
},
appicon_padding_scale_value_changed_cb: function(scale) {
// Avoid settings the size consinuosly
if (this._appicon_padding_timeout > 0)
Mainloop.source_remove(this._appicon_padding_timeout);
this._appicon_padding_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() {
this._settings.set_int('appicon-padding', scale.get_value());
this._appicon_padding_timeout = 0;
return GLib.SOURCE_REMOVE;
}));
},
tray_padding_scale_format_value_cb: function(scale, value) {
return value+ ' px';
},
tray_padding_scale_value_changed_cb: function(scale) {
// Avoid settings the size consinuosly
if (this._tray_padding_timeout > 0)
Mainloop.source_remove(this._tray_padding_timeout);
this._tray_padding_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() {
this._settings.set_int('tray-padding', scale.get_value());
this._tray_padding_timeout = 0;
return GLib.SOURCE_REMOVE;
}));
},
statusicon_padding_scale_format_value_cb: function(scale, value) {
return value+ ' px';
},
statusicon_padding_scale_value_changed_cb: function(scale) {
// Avoid settings the size consinuosly
if (this._statusicon_padding_timeout > 0)
Mainloop.source_remove(this._statusicon_padding_timeout);
this._statusicon_padding_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() {
this._settings.set_int('status-icon-padding', scale.get_value());
this._statusicon_padding_timeout = 0;
return GLib.SOURCE_REMOVE;
}));
},
leftbox_padding_scale_format_value_cb: function(scale, value) {
return value+ ' px';
},
leftbox_padding_scale_value_changed_cb: function(scale) {
// Avoid settings the size consinuosly
if (this._leftbox_padding_timeout > 0)
Mainloop.source_remove(this._leftbox_padding_timeout);
this._leftbox_padding_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() {
this._settings.set_int('leftbox-padding', scale.get_value());
this._leftbox_padding_timeout = 0;
return GLib.SOURCE_REMOVE;
}));
}
}
});
function init() {
Convenience.initTranslations();
}
function buildPrefsWidget() {
let settings = new Settings();
let widget = settings.widget;
// I'd like the scrolled window to default to a size large enough to show all without scrolling, if it fits on the screen
// But, it doesn't seem possible, so I'm setting a minimum size if there seems to be enough screen real estate
widget.show_all();
adjustScrollableHeight(settings.viewport, widget);
return widget;
}
function adjustScrollableHeight(viewport, scrollableWindow) {
let viewportSize = viewport.size_request();
let screenHeight = scrollableWindow.get_screen().get_height() - 120;
scrollableWindow.set_size_request(viewportSize.width, viewportSize.height > screenHeight ? screenHeight : viewportSize.height);
}
\ No newline at end of file
/*
* This file is part of the Dash-To-Panel extension for Gnome 3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
const Lang = imports.lang;
const Meta = imports.gi.Meta;
const Layout = imports.ui.layout;
const Main = imports.ui.main;
const Me = imports.misc.extensionUtils.getCurrentExtension();
const Utils = Me.imports.utils;
//timeout intervals
const MIN_UPDATE_MS = 200;
//timeout names
const T1 = 'limitUpdateTimeout';
var Mode = {
ALL_WINDOWS: 0,
FOCUSED_WINDOWS: 1,
MAXIMIZED_WINDOWS: 2
};
var ProximityWatch = Utils.defineClass({
Name: 'DashToPanel.ProximityWatch',
_init: function(actor, mode, xThreshold, yThreshold, handler) {
this.actor = actor;
this.overlap = 0;
this.mode = mode;
this.threshold = [xThreshold, yThreshold];
this.handler = handler;
this._allocationChangedId = actor.connect('allocation-changed', () => this._update());
this._update();
},
destroy: function() {
this.actor.disconnect(this._allocationChangedId);
},
_update: function() {
this.monitorIndex = Main.layoutManager.findIndexForActor(this.actor);
this._updateWatchRect();
},
_updateWatchRect: function() {
let [actorX, actorY] = this.actor.get_position();
this.rect = new Meta.Rectangle({
x: actorX - this.threshold[0],
y: actorY - this.threshold[1],
width: this.actor.width + this.threshold[0] * 2,
height: this.actor.height + this.threshold[1] * 2
});
},
});
var ProximityManager = Utils.defineClass({
Name: 'DashToPanel.ProximityManager',
_init: function() {
this._counter = 1;
this._watches = {};
this._focusedWindowInfo = null;
this._signalsHandler = new Utils.GlobalSignalsHandler();
this._timeoutsHandler = new Utils.TimeoutsHandler();
this._bindSignals();
this._setFocusedWindow();
},
createWatch: function(actor, mode, xThreshold, yThreshold, handler) {
let watch = new ProximityWatch(actor, mode, xThreshold, yThreshold, handler);
this._watches[this._counter] = watch;
this.update();
return this._counter++;
},
removeWatch: function(id) {
if (this._watches[id]) {
this._watches[id].destroy();
delete this._watches[id];
}
},
update: function() {
this._queueUpdate(true);
},
destroy: function() {
this._signalsHandler.destroy();
this._timeoutsHandler.destroy();
this._disconnectFocusedWindow();
Object.keys(this._watches).forEach(id => this.removeWatch(id));
},
_bindSignals: function() {
this._signalsHandler.add(
[
global.window_manager,
'switch-workspace',
() => Object.keys(this._watches).forEach(id => this._watches[id].overlap = 0)
],
[
global.display,
'notify::focus-window',
() => {
this._setFocusedWindow();
this._queueUpdate();
}
],
[
global.window_group,
[
'actor-added',
'actor-removed'
],
() => this._queueUpdate()
]
);
},
_setFocusedWindow: function() {
this._disconnectFocusedWindow();
let focusedWindow = global.display.focus_window;
if (focusedWindow) {
let focusedWindowInfo = this._getFocusedWindowInfo(focusedWindow);
if (focusedWindowInfo && this._checkIfHandledWindowType(focusedWindowInfo.metaWindow)) {
focusedWindowInfo.allocationId = focusedWindowInfo.window.connect('allocation-changed', () => this._queueUpdate());
focusedWindowInfo.destroyId = focusedWindowInfo.window.connect('destroy', () => this._disconnectFocusedWindow(true));
this._focusedWindowInfo = focusedWindowInfo;
}
}
},
_getFocusedWindowInfo: function(focusedWindow) {
let window = focusedWindow.get_compositor_private();
let focusedWindowInfo;
if (window) {
focusedWindowInfo = { window: window };
focusedWindowInfo.metaWindow = focusedWindowInfo.window.get_meta_window();
if (focusedWindow.is_attached_dialog()) {
let mainMetaWindow = focusedWindow.get_transient_for();
if (focusedWindowInfo.metaWindow.get_frame_rect().height < mainMetaWindow.get_frame_rect().height) {
focusedWindowInfo.window = mainMetaWindow.get_compositor_private();
focusedWindowInfo.metaWindow = mainMetaWindow;
}
}
}
return focusedWindowInfo;
},
_disconnectFocusedWindow: function(destroy) {
if (this._focusedWindowInfo && !destroy) {
this._focusedWindowInfo.window.disconnect(this._focusedWindowInfo.allocationId);
this._focusedWindowInfo.window.disconnect(this._focusedWindowInfo.destroyId);
}
this._focusedWindowInfo = null;
},
_getHandledWindows: function() {
return global.get_window_actors()
.filter(w => w.visible)
.map(w => w.get_meta_window())
.filter(mw => this._checkIfHandledWindow(mw));
},
_checkIfHandledWindow: function(metaWindow) {
return metaWindow && !metaWindow.minimized &&
this._checkIfHandledWindowType(metaWindow);
},
_checkIfHandledWindowType: function(metaWindow) {
let metaWindowType = metaWindow.get_window_type();
//https://www.roojs.org/seed/gir-1.2-gtk-3.0/seed/Meta.WindowType.html
return metaWindowType <= Meta.WindowType.SPLASHSCREEN &&
metaWindowType != Meta.WindowType.DESKTOP;
},
_queueUpdate: function(noDelay) {
if (!noDelay && this._timeoutsHandler.getId(T1)) {
//limit the number of updates
this._pendingUpdate = true;
return;
}
this._timeoutsHandler.add([T1, MIN_UPDATE_MS, () => this._endLimitUpdate()]);
let metaWindows = this._getHandledWindows();
Object.keys(this._watches).forEach(id => {
let watch = this._watches[id];
let overlap = this._update(watch, metaWindows);
if (overlap !== watch.overlap) {
watch.handler(overlap);
watch.overlap = overlap;
}
});
},
_endLimitUpdate: function() {
if (this._pendingUpdate) {
this._pendingUpdate = false;
this._queueUpdate();
}
},
_update: function(watch, metaWindows) {
if (watch.mode === Mode.FOCUSED_WINDOWS) {
return (this._focusedWindowInfo &&
this._checkIfHandledWindow(this._focusedWindowInfo.metaWindow) &&
this._checkProximity(this._focusedWindowInfo.metaWindow, watch));
} else if (watch.mode === Mode.MAXIMIZED_WINDOWS) {
return metaWindows.some(mw => mw.maximized_vertically && mw.maximized_horizontally &&
mw.get_monitor() == watch.monitorIndex);
}
//Mode.ALL_WINDOWS
return metaWindows.some(mw => this._checkProximity(mw, watch));
},
_checkProximity: function(metaWindow, watch) {
return metaWindow.get_frame_rect().overlap(watch.rect);
},
});
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<schemalist gettext-domain="gnome-shell-extensions">
<enum id='org.gnome.shell.extensions.dash-to-panel.dotStyle'>
<value value='0' nick='DOTS'/>
<value value='1' nick='SQUARES'/>
<value value='2' nick='DASHES'/>
<value value='3' nick='SEGMENTED'/>
<value value='4' nick='SOLID'/>
<value value='5' nick='CILIORA'/>
<value value='6' nick='METRO'/>
</enum>
<enum id='org.gnome.shell.extensions.dash-to-panel.clickAction'>
<value value='0' nick='RAISE'/>
<value value='1' nick='MINIMIZE'/>
<value value='2' nick='LAUNCH'/>
<value value='3' nick='CYCLE'/>
<value value='4' nick='CYCLE-MIN'/>
<value value='5' nick='QUIT'/>
<value value='6' nick='TOGGLE-SHOWPREVIEW'/>
</enum>
<enum id='org.gnome.shell.extensions.dash-to-panel.scrollAction'>
<value value='0' nick='NOTHING'/>
<value value='1' nick='SWITCH_WORKSPACE'/>
<value value='2' nick='CYCLE_WINDOWS'/>
<value value='3' nick='PASS_THROUGH'/>
</enum>
<enum id='org.gnome.shell.extensions.dash-to-panel.statusAreaPosition'>
<value value='0' nick='BUTTONSLEFT'/>
<value value='1' nick='STATUSLEFT'/>
<value value='2' nick='STATUSRIGHT'/>
<value value='3' nick='BUTTONSRIGHT'/>
<value value='4' nick='TASKBARLEFT'/>
<value value='5' nick='TASKBARRIGHT'/>
</enum>
<enum id='org.gnome.shell.extensions.dash-to-panel.taskbarPosition'>
<value value='0' nick='LEFTPANEL'/>
<value value='1' nick='CENTEREDMONITOR'/>
<value value='2' nick='CENTEREDCONTENT'/>
<value value='3' nick='LEFTPANEL_FIXEDCENTER'/>
<value value='4' nick='LEFTPANEL_FLOATCENTER'/>
</enum>
<enum id='org.gnome.shell.extensions.dash-to-panel.hotkeyPrefix'>
<value value='0' nick='Super'/>
<value value='1' nick='SuperAlt'/>
</enum>
<enum id='org.gnome.shell.extensions.dash-to-panel.hotkeyOverlay'>
<value value='0' nick='NEVER'/>
<value value='1' nick='TEMPORARILY'/>
<value value='2' nick='ALWAYS'/>
</enum>
<enum id='org.gnome.shell.extensions.dash-to-panel.position'>
<value value='0' nick='BOTTOM'/>
<value value='1' nick='TOP'/>
<value value='2' nick='LEFT'/>
<value value='3' nick='RIGHT'/>
</enum>
<enum id='org.gnome.shell.extensions.dash-to-panel.proximityBehavior'>
<value value='0' nick='ALL_WINDOWS'/>
<value value='1' nick='FOCUSED_WINDOWS'/>
<value value='2' nick='MAXIMIZED_WINDOWS'/>
</enum>
<enum id='org.gnome.shell.extensions.dash-to-panel.fontWeight'>
<value value='0' nick='inherit'/>
<value value='1' nick='normal'/>
<value value='2' nick='lighter'/>
<value value='3' nick='bold'/>
<value value='4' nick='bolder'/>
</enum>
<enum id='org.gnome.shell.extensions.dash-to-panel.hotkeyNumberKeys'>
<value value='0' nick='NUM_ROW'/>
<value value='1' nick='NUM_KEYPAD'/>
<value value='2' nick='BOTH'/>
</enum>
<schema path="/org/gnome/shell/extensions/dash-to-panel/" id="org.gnome.shell.extensions.dash-to-panel">
<key type="b" name="check-update">
<default>false</default>
</key>
<key type="b" name="force-check-update">
<default>false</default>
</key>
<key type="s" name="version-to-install">
<default>''</default>
</key>
<key name="panel-position" enum="org.gnome.shell.extensions.dash-to-panel.position">
<default>'BOTTOM'</default>
<summary>Panel position</summary>
<description>Panel is shown on the Bottom or Top of the screen.</description>
</key>
<key type="i" name="panel-size">
<default>48</default>
<summary>Panel size</summary>
<description>Set the size of the panel.</description>
</key>
<key name="dot-position" enum="org.gnome.shell.extensions.dash-to-panel.position">
<default>'BOTTOM'</default>
<summary>Dot position</summary>
<description>Running indicators are shown on the Bottom or Top of the screen.</description>
</key>
<key name="dot-style-focused" enum="org.gnome.shell.extensions.dash-to-panel.dotStyle">
<default>'METRO'</default>
<summary>Style of the running indicator (focused)</summary>
<description>Style of the running indicator for the icon for the currently focused application</description>
</key>
<key name="dot-style-unfocused" enum="org.gnome.shell.extensions.dash-to-panel.dotStyle">
<default>'METRO'</default>
<summary>Style of the running indicator (unfocused)</summary>
<description>Style of the running indicator for the icon for applications which are not currently focused</description>
</key>
<key type="b" name="dot-color-dominant">
<default>false</default>
<summary>Running indicator dominant color</summary>
<description>Whether to use the app icon's dominant color for .app-well-running-dot</description>
</key>
<key type="b" name="dot-color-override">
<default>false</default>
<summary>Running indicator color override</summary>
<description>Whether to override the theme background color for .app-well-running-dot</description>
</key>
<key type="s" name="dot-color-1">
<default>"#5294e2"</default>
<summary>Color of running indicator (1 window)</summary>
<description>Customize the color of the running indicator when one window is running for that application</description>
</key>
<key type="s" name="dot-color-2">
<default>"#5294e2"</default>
<summary>Color of running indicator (2 windows)</summary>
<description>Customize the color of the running indicator when two windows are running for that application</description>
</key>
<key type="s" name="dot-color-3">
<default>"#5294e2"</default>
<summary>Color of running indicator (3 windows)</summary>
<description>Customize the color of the running indicator when three windows are running for that application</description>
</key>
<key type="s" name="dot-color-4">
<default>"#5294e2"</default>
<summary>Color of running indicator (4+ windows)</summary>
<description>Customize the color of the running indicator when four or more windows are running for that application</description>
</key>
<key type="b" name="dot-color-unfocused-different">
<default>false</default>
<summary>Unfocused color is different than focused</summary>
<description>Whether to apply a 2nd color scheme to the indicator when the app is not focused</description>
</key>
<key type="s" name="dot-color-unfocused-1">
<default>"#5294e2"</default>
<summary>Color of unfocused running indicator (1 window)</summary>
<description>Customize the color of the unfocused running indicator when one window is running for that application</description>
</key>
<key type="s" name="dot-color-unfocused-2">
<default>"#5294e2"</default>
<summary>Color of unfocused running indicator (2 windows)</summary>
<description>Customize the color of the unfocused running indicator when two windows are running for that application</description>
</key>
<key type="s" name="dot-color-unfocused-3">
<default>"#5294e2"</default>
<summary>Color of unfocused running indicator (3 windows)</summary>
<description>Customize the color of the unfocused running indicator when three windows are running for that application</description>
</key>
<key type="s" name="dot-color-unfocused-4">
<default>"#5294e2"</default>
<summary>Color of unfocused running indicator (4+ windows)</summary>
<description>Customize the color of the unfocused running indicator when four or more windows are running for that application</description>
</key>
<key type="i" name="dot-size">
<default>3</default>
<summary>Running indicator height</summary>
<description>Height of the running indicator line/diameter of window indicator dots</description>
</key>
<key type="b" name="focus-highlight">
<default>true</default>
<summary>Highlight icon of focused application</summary>
<description>Whether to highlight the background of the currently focused application's icon</description>
</key>
<key type="b" name="focus-highlight-dominant">
<default>false</default>
<summary>Highlight icon dominant color</summary>
<description>Base the active window highlight color on that application's icon</description>
</key>
<key type="s" name="focus-highlight-color">
<default>"#EEEEEE"</default>
<summary>Color of highlight of focused application</summary>
<description>Customize the color of the highlight of the focused application</description>
</key>
<key type="i" name="focus-highlight-opacity">
<default>25</default>
<summary>Opacity of highlight of focused application</summary>
<description>Customize the opacity of the highlight of the focused application</description>
</key>
<key type="b" name="stockgs-keep-dash">
<default>false</default>
<summary>Keep dash</summary>
<description>Whether to keep the stock gnome-shell dash while in overview</description>
</key>
<key type="b" name="stockgs-panelbtn-click-only">
<default>false</default>
<summary>Panel menu buttons require click</summary>
<description>Whether to activate the panel menu buttons on hover or on click</description>
</key>
<key name="location-clock" enum="org.gnome.shell.extensions.dash-to-panel.statusAreaPosition">
<default>'STATUSLEFT'</default>
<summary>Location of the clock</summary>
<description>Set the location of the clock on the taskbar</description>
</key>
<key name="taskbar-position" enum="org.gnome.shell.extensions.dash-to-panel.taskbarPosition">
<default>'LEFTPANEL'</default>
<summary>Position of the taskbar</summary>
<description>Set the position of the taskbar on the panel</description>
</key>
<key type="b" name="taskbar-locked">
<default>false</default>
<summary>Lock the taskbar</summary>
<description>Specifies if the user can modify the taskbar</description>
</key>
<key type="b" name="trans-use-custom-bg">
<default>false</default>
<summary>Override theme background color</summary>
<description>Replace current theme background color for the panel</description>
</key>
<key type="s" name="trans-bg-color">
<default>"#000"</default>
<summary>Custom background color</summary>
<description>Custom background color for the panel</description>
</key>
<key type="b" name="trans-use-custom-opacity">
<default>false</default>
<summary>Custom background color</summary>
<description>Replace current theme background color for the panel</description>
</key>
<key type="b" name="trans-use-dynamic-opacity">
<default>false</default>
<summary>Dynamic opacity</summary>
<description>Enable dynamic opacity</description>
</key>
<key type="d" name="trans-panel-opacity">
<default>0.4</default>
<summary>Panel opacity</summary>
<description>Custom opacity for the panel</description>
</key>
<key name="trans-dynamic-behavior" enum="org.gnome.shell.extensions.dash-to-panel.proximityBehavior">
<default>'ALL_WINDOWS'</default>
<summary>Dynamic opacity behavior</summary>
<description>Dictates which window type affects the panel opacity</description>
</key>
<key type="i" name="trans-dynamic-distance">
<default>20</default>
<summary>Distance to change opacity</summary>
<description>The distance a window needs to be from the panel to change opacity</description>
</key>
<key type="d" name="trans-dynamic-anim-target">
<default>0.8</default>
<summary>Modified panel opacity</summary>
<description>Modified opacity for the panel when a window is near</description>
</key>
<key type="i" name="trans-dynamic-anim-time">
<default>300</default>
<summary>Opacity change duration</summary>
<description>The duration of the animation when the opacity changes</description>
</key>
<key type="b" name="trans-use-custom-gradient">
<default>false</default>
<summary>Custom gradient</summary>
<description>Replace current theme gradient for the panel</description>
</key>
<key type="s" name="trans-gradient-top-color">
<default>"#000"</default>
<summary>Custom gradient top color</summary>
<description>Custom gradient top color for the panel</description>
</key>
<key type="d" name="trans-gradient-top-opacity">
<default>0</default>
<summary>Custom gradient top opacity</summary>
<description>Custom gradient top opacity for the panel</description>
</key>
<key type="s" name="trans-gradient-bottom-color">
<default>"#000"</default>
<summary>Custom gradient bottom color</summary>
<description>Custom gradient bottom color for the panel</description>
</key>
<key type="d" name="trans-gradient-bottom-opacity">
<default>0.2</default>
<summary>Custom gradient bottom opacity</summary>
<description>Custom gradient bottom opacity for the panel</description>
</key>
<key type="b" name="intellihide">
<default>false</default>
<summary>Intellihide</summary>
<description>Whether to intelligently hide the panel</description>
</key>
<key type="b" name="intellihide-hide-from-windows">
<default>false</default>
<summary>Only hide from windows</summary>
<description>Dictates if the dash should only hide when in conflict with windows</description>
</key>
<key name="intellihide-behaviour" enum="org.gnome.shell.extensions.dash-to-panel.proximityBehavior">
<default>'FOCUSED_WINDOWS'</default>
<summary>Intellihide behaviour</summary>
<description>Dictates how to intelligently hide the panel</description>
</key>
<key type="b" name="intellihide-use-pressure">
<default>false</default>
<summary>Intellihide pressure</summary>
<description>To reveal the panel, pressure needs to be applied to the edege of the screen</description>
</key>
<key type="i" name="intellihide-pressure-threshold">
<default>100</default>
<summary>Intellihide pressure threshold</summary>
<description>The pressure needed to reveal the panel</description>
</key>
<key type="i" name="intellihide-pressure-time">
<default>1000</default>
<summary>Intellihide pressure time</summary>
<description>The numer of milliseconds that the pressure needs to be applied to reveal the panel</description>
</key>
<key type="b" name="intellihide-show-in-fullscreen">
<default>false</default>
<summary>Intellihide pressure</summary>
<description>Allow the panel to be revealed while an application is in fullscreen mode</description>
</key>
<key type="b" name="intellihide-only-secondary">
<default>false</default>
<summary>Intellihide only secondary</summary>
<description>Whether to only hide secondary panels</description>
</key>
<key type="i" name="intellihide-animation-time">
<default>200</default>
<summary>Intellihide animation time</summary>
<description>The animation time (ms) to hide and reveal the panel</description>
</key>
<key type="i" name="intellihide-close-delay">
<default>400</default>
<summary>Intellihide close delay</summary>
<description>The delay (ms) before hiding the panel</description>
</key>
<key type="s" name="intellihide-key-toggle-text">
<default>"&lt;Super&gt;i"</default>
<summary>Keybinding toggle intellihide</summary>
<description>Keybinding to reveal the panel while in intellihide mode</description>
</key>
<key type="as" name="intellihide-key-toggle">
<default><![CDATA[['<Super>i']]]></default>
<summary>Keybinding toggle intellihide</summary>
<description>Keybinding to reveal the panel while in intellihide mode</description>
</key>
<key type="i" name="intellihide-enable-start-delay">
<default>2000</default>
<summary>Intellihide enable start delay</summary>
<description>The delay before enabling intellihide on start</description>
</key>
<key type="b" name="show-show-apps-button">
<default>true</default>
<summary>Show applications button</summary>
<description>Show appplications button in the dash</description>
</key>
<key type="s" name="show-apps-icon-file">
<default>""</default>
<summary>Custom Show Applications icon</summary>
<description>Customize the Show Applications icon</description>
</key>
<key type="i" name="show-apps-icon-side-padding">
<default>8</default>
<summary>Show Applications icon side padding</summary>
<description>Customize the Show Applications icon side padding</description>
</key>
<key type="b" name="animate-show-apps">
<default>true</default>
<summary>Animate Show Applications from the desktop</summary>
<description>Animate Show Applications from the desktop</description>
</key>
<key type="b" name="show-activities-button">
<default>false</default>
<summary>Show activities button</summary>
<description>Show activities button on the left hand side of the taskbar</description>
</key>
<key type="b" name="show-showdesktop-button">
<default>true</default>
<summary>Show desktop button</summary>
<description>Show button on right side of bar that minimizes/restores all visible windows on current workspace</description>
</key>
<key type="i" name="showdesktop-button-width">
<default>8</default>
<summary>Width of show Desktop button</summary>
<description>Customize the width of the show Desktop button</description>
</key>
<key type="b" name="show-showdesktop-hover">
<default>false</default>
<summary>Show desktop on hover</summary>
<description>Show the desktop on mouse hover</description>
</key>
<key type="i" name="show-showdesktop-delay">
<default>1000</default>
<summary>Delay show desktop</summary>
<description>Delay before showing the desktop</description>
</key>
<key type="i" name="show-showdesktop-time">
<default>300</default>
<summary>Show desktop animation time</summary>
<description>Window fade animation time when showing the destop</description>
</key>
<key type="b" name="show-appmenu">
<default>false</default>
<summary>Show appMenu button</summary>
<description>Show appMenu on the right hand side of the panel</description>
</key>
<key type="b" name="show-window-previews">
<default>true</default>
<summary>Show window preview</summary>
<description>Show preview of running window on hover of app icon</description>
</key>
<key type="b" name="show-tooltip">
<default>true</default>
<summary>Show tooltip</summary>
<description>Show tooltip on hover of app icon</description>
</key>
<key type="b" name="show-running-apps">
<default>true</default>
<summary>Show running apps</summary>
<description>Show or hide running application icons in the dash</description>
</key>
<key type="b" name="show-favorites">
<default>true</default>
<summary>Show favorites apps</summary>
<description>Show or hide favorite application icons in the dash</description>
</key>
<key type="i" name="show-window-previews-timeout">
<default>100</default>
<summary>Icon enter display time</summary>
<description>Amount of time after entering icon to wait before displaying window preview if icon is not clicked or mouse has not left.</description>
</key>
<key type="b" name="peek-mode">
<default>true</default>
<summary>Enable peek mode</summary>
<description>Peek a window upon hover for some time</description>
</key>
<key type="b" name="window-preview-show-title">
<default>true</default>
<summary>Display title in preview</summary>
<description>Display window title in preview</description>
</key>
<key type="b" name="window-preview-manual-styling">
<default>false</default>
<summary>Window previews manual styling</summary>
<description>This defines if the default window previews styling should be applied</description>
</key>
<key name="window-preview-title-position" enum="org.gnome.shell.extensions.dash-to-panel.position">
<default>'TOP'</default>
<summary>Title position</summary>
<description>Position of the window title, close button and icon in preview.</description>
</key>
<key type="s" name="window-preview-title-font-color">
<default>"#dddddd"</default>
<summary>Window previews title font color</summary>
<description>This defines the window preview titles font color.</description>
</key>
<key type="i" name="window-preview-title-font-size">
<default>14</default>
<summary>Window previews title font size</summary>
<description>This defines the window preview titles font size.</description>
</key>
<key type="i" name="window-preview-animation-time">
<default>260</default>
<summary>Window previews animation time</summary>
<description>This defines the window previews animation time.</description>
</key>
<key name="window-preview-title-font-weight" enum="org.gnome.shell.extensions.dash-to-panel.fontWeight">
<default>'inherit'</default>
<summary>Font weight of window preview titles</summary>
<description>This defines the font weight of window preview titles. Supported values: inherit (from theme), normal, lighter, bold and bolder.</description>
</key>
<key type="i" name="window-preview-size">
<default>240</default>
<summary>Window previews size</summary>
<description>Preferred window previews size</description>
</key>
<key type="b" name="window-preview-fixed-x">
<default>false</default>
<summary>Fixed aspect ratio X</summary>
<description>This defines if the window previews use a fixed aspect ratio X.</description>
</key>
<key type="b" name="window-preview-fixed-y">
<default>true</default>
<summary>Fixed aspect ratio Y</summary>
<description>This defines if the window previews use a fixed aspect ratio Y.</description>
</key>
<key type="i" name="window-preview-padding">
<default>8</default>
<summary>Window previews padding</summary>
<description>The padding of the window previews</description>
</key>
<key type="i" name="window-preview-aspect-ratio-x">
<default>16</default>
<summary>Aspect ratio X</summary>
<description>The window previews respected aspect ratio X.</description>
</key>
<key type="i" name="window-preview-aspect-ratio-y">
<default>9</default>
<summary>Aspect ratio Y</summary>
<description>The window previews respected aspect ratio Y.</description>
</key>
<key type="b" name="window-preview-hide-immediate-click">
<default>false</default>
<summary>Immediate hide on icon click</summary>
<description>The window previews immediately hide when an application icon is clicked.</description>
</key>
<key type="b" name="isolate-workspaces">
<default>false</default>
<summary>Provide workspace isolation</summary>
<description>Dash shows only windows from the current workspace</description>
</key>
<key type="b" name="group-apps">
<default>true</default>
<summary>Group applications</summary>
<description>Dash groups the application instances under the same icon</description>
</key>
<key type="i" name="group-apps-label-font-size">
<default>14</default>
<summary>Application title font size</summary>
<description>When the applications are ungrouped, this defines the application titles font size.</description>
</key>
<key name="group-apps-label-font-weight" enum="org.gnome.shell.extensions.dash-to-panel.fontWeight">
<default>'inherit'</default>
<summary>Font weight of application titles</summary>
<description>When the applications are ungrouped, this defines font weight of application titles. Supported values: inherit (from theme), normal, lighter, bold and bolder.</description>
</key>
<key type="s" name="group-apps-label-font-color">
<default>"#dddddd"</default>
<summary>Application title font color</summary>
<description>When the applications are ungrouped, this defines the application titles font color.</description>
</key>
<key type="i" name="group-apps-label-max-width">
<default>160</default>
<summary>Application title max width</summary>
<description>When the applications are ungrouped, this defines the application titles maximum width.</description>
</key>
<key type="b" name="group-apps-use-fixed-width">
<default>true</default>
<summary>Use a fixed width for the application titles</summary>
<description>The application titles all have the same width, even if their texts are shorter than the maximum width. The maximum width value is used as the fixed width.</description>
</key>
<key type="b" name="group-apps-underline-unfocused">
<default>true</default>
<summary>Display running indicators on unfocused applications</summary>
<description>When the applications are ungrouped, this defines if running applications should display an indicator.</description>
</key>
<key type="b" name="group-apps-use-launchers">
<default>false</default>
<summary>Use favorite icons as application launchers</summary>
<description>When the applications are ungrouped, this defines if running applications stay separate from the favorite icons.</description>
</key>
<key type="i" name="primary-monitor">
<default>-1</default>
<summary>Primary monitor index</summary>
<description>Specifies the index of the primary monitor (-1 = GNOME Primary Monitor).</description>
</key>
<key type="b" name="multi-monitors">
<default>true</default>
<summary>Display panels on all monitors</summary>
<description>Specifies if a panel is shown on every monitors</description>
</key>
<key type="b" name="isolate-monitors">
<default>false</default>
<summary>Provide monitor isolation</summary>
<description>Dash shows only windows from the current monitor</description>
</key>
<key type="b" name="show-clock-all-monitors">
<default>true</default>
<summary>Display the clock on all monitors</summary>
<description>Specifies if every panel should display the clock. If false, the clock is only displayed on the primary monitor.</description>
</key>
<key type="b" name="show-status-menu-all-monitors">
<default>true</default>
<summary>Display the status menu on all monitors</summary>
<description>Specifies if every panel should display the status menu. If false, the status menu is only displayed on the primary monitor.</description>
</key>
<key type="b" name="show-favorites-all-monitors">
<default>true</default>
<summary>Display the favorites on all monitors</summary>
<description>Specifies if every panel should display the favorite applications. If false, the favorite appplications are only displayed on the primary monitor.</description>
</key>
<key type="b" name="customize-click">
<default>true</default>
<summary>Customize click behaviour</summary>
<description>Customize action on various mouse events</description>
</key>
<key type="b" name="minimize-shift">
<default>true</default>
<summary>Minimize on shift+click</summary>
</key>
<key type="b" name="activate-single-window">
<default>true</default>
<summary>Activate only one window</summary>
</key>
<key name="click-action" enum="org.gnome.shell.extensions.dash-to-panel.clickAction">
<default>'CYCLE-MIN'</default>
<summary>Action when clicking on a running app</summary>
<description>Set the action that is executed when clicking on the icon of a running application</description>
</key>
<key name="shift-click-action" enum="org.gnome.shell.extensions.dash-to-panel.clickAction">
<default>'MINIMIZE'</default>
<summary>Action when shift+clicking on a running app</summary>
<description>Set the action that is executed when shift+clicking on the icon of a running application</description>
</key>
<key name="middle-click-action" enum="org.gnome.shell.extensions.dash-to-panel.clickAction">
<default>'LAUNCH'</default>
<summary>Action when clicking on a running app</summary>
<description>Set the action that is executed when middle-clicking on the icon of a running application</description>
</key>
<key name="shift-middle-click-action" enum="org.gnome.shell.extensions.dash-to-panel.clickAction">
<default>'LAUNCH'</default>
<summary>Action when clicking on a running app</summary>
<description>Set the action that is executed when shift+middle-clicking on the icon of a running application</description>
</key>
<key name="scroll-panel-action" enum="org.gnome.shell.extensions.dash-to-panel.scrollAction">
<default>'SWITCH_WORKSPACE'</default>
<summary>Action when scrolling over the panel</summary>
<description>Set the action that is executed when scrolling over the panel</description>
</key>
<key type="i" name="scroll-panel-delay">
<default>0</default>
<summary>Delay between panel mouse scroll events</summary>
<description>Set the minimum delay between panel mouse scroll events</description>
</key>
<key name="scroll-icon-action" enum="org.gnome.shell.extensions.dash-to-panel.scrollAction">
<default>'CYCLE_WINDOWS'</default>
<summary>Action when scrolling over a running app</summary>
<description>Set the action that is executed when scrolling over a running application</description>
</key>
<key type="i" name="scroll-icon-delay">
<default>0</default>
<summary>Delay between icon mouse scroll events</summary>
<description>Set the minimum delay between icon mouse scroll events</description>
</key>
<key type="i" name="leave-timeout">
<default>100</default>
<summary>Icon leave preview timeout</summary>
<description>Amount of time to leave preview windows open when the mouse has left the application's icon.</description>
</key>
<key type="i" name="enter-peek-mode-timeout">
<default>500</default>
<summary>Enter window peeking mode timeout</summary>
<description>Amount of time of inactivity to enter the window peeking mode when the mouse has entered a window preview.</description>
</key>
<key type="i" name="peek-mode-opacity">
<default>40</default>
<summary>Window peeking mode opacity</summary>
<description>All windows except for the peeked one have their opacity set to the same value.</description>
</key>
<key type="b" name="preview-middle-click-close">
<default>true</default>
<summary>Middle click preview to close window</summary>
<description>Middle click on the window preview to close that window</description>
</key>
<key type="b" name="preview-use-custom-opacity">
<default>true</default>
<summary>Window previews use custom opacity</summary>
<description>Window previews background use a different opacity from the panel</description>
</key>
<key type="i" name="preview-custom-opacity">
<default>80</default>
<summary>Window previews background opacity</summary>
<description>Window previews use this custom background opacity.</description>
</key>
<key type="i" name="tray-size">
<default>0</default>
<summary>Tray font size</summary>
<description>Set the size of the tray font. (0 for default)</description>
</key>
<key type="i" name="leftbox-size">
<default>0</default>
<summary>Leftbox font size</summary>
<description>Set the size of the leftBox font. (0 for default)</description>
</key>
<key type="i" name="appicon-margin">
<default>8</default>
<summary>App icon margin</summary>
<description>Set the margin for application icons in the embedded dash.</description>
</key>
<key type="i" name="appicon-padding">
<default>4</default>
<summary>App icon padding</summary>
<description>Set the padding for application icons in the embedded dash.</description>
</key>
<key type="i" name="tray-padding">
<default>-1</default>
<summary>Tray item padding</summary>
<description>Set the size of the tray padding. (-1 for default)</description>
</key>
<key type="i" name="leftbox-padding">
<default>-1</default>
<summary>Leftbox item padding</summary>
<description>Set the size of the leftBox padding. (-1 for default)</description>
</key>
<key type="i" name="status-icon-padding">
<default>-1</default>
<summary>Status icon padding</summary>
<description>Set the size of the aggregate (status) menu icon padding. (-1 for default)</description>
</key>
<key type="b" name="animate-app-switch">
<default>true</default>
<summary>Animate running indicator when open/closing/switching applications</summary>
</key>
<key type="b" name="animate-window-launch">
<default>true</default>
<summary>Animate when new window launched</summary>
</key>
<key type="b" name="secondarymenu-contains-appmenu">
<default>true</default>
<summary>Integrate items from the gnome appmenu into the right click menu</summary>
</key>
<key type="b" name="secondarymenu-contains-showdetails">
<default>false</default>
<summary>Display Show Details to open Gnome Software from right click menu</summary>
</key>
<key type="s" name="shortcut-text">
<default>"&lt;Super&gt;q"</default>
<summary>Keybinding to show the dock and the number overlay.</summary>
<description>Behavior depends on hotkeys-show-dock and hotkeys-overlay.</description>
</key>
<key type="as" name="shortcut">
<default><![CDATA[['<Super>q']]]></default>
<summary>Keybinding to show the dock and the number overlay.</summary>
<description>Behavior depends on hotkeys-show-dock and hotkeys-overlay.</description>
</key>
<key type="i" name="shortcut-timeout">
<default>2000</default>
<summary>Timeout to hide the dock, in seconds</summary>
<description>Sets the time duration before the dock is hidden again.</description>
</key>
<key type="i" name="overlay-timeout">
<default>750</default>
<summary>Timeout to hide the dock, in seconds</summary>
<description>Sets the time duration before the dock is hidden again.</description>
</key>
<key name="hotkeys-overlay-combo" enum="org.gnome.shell.extensions.dash-to-panel.hotkeyOverlay">
<default>'TEMPORARILY'</default>
<summary>Transitivity of the number overlay</summary>
<description>You can choose between NEVER, TEMPORARILY and ALWAYS.</description>
</key>
<key type="b" name="hot-keys">
<default>false</default>
<summary>Super Hot-Keys</summary>
<description>Launch and switch between dash items using Super+(0-9)</description>
</key>
<key name="hotkey-prefix-text" enum="org.gnome.shell.extensions.dash-to-panel.hotkeyPrefix">
<default>'Super'</default>
<summary>Prefix to use for hotkeys</summary>
<description>You can choose between Super or SuperAlt as the prefix for hotkeys.</description>
</key>
<key type="b" name="shortcut-previews">
<default>false</default>
<summary>Show window previews</summary>
<description>When multiple instances of the application are available, show their window previews</description>
</key>
<key name="shortcut-num-keys" enum="org.gnome.shell.extensions.dash-to-panel.hotkeyNumberKeys">
<default>'BOTH'</default>
<summary>Hotkeys number keys</summary>
<description>Which number keys are used for the hotkeys</description>
</key>
<key name="app-ctrl-hotkey-1" type="as">
<default><![CDATA[['<Ctrl><Super>1']]]></default>
<summary>Keybinding to launch 1st dash app</summary>
<description>
Keybinding to launch 1st app.
</description>
</key>
<key name="app-ctrl-hotkey-2" type="as">
<default><![CDATA[['<Ctrl><Super>2']]]></default>
<summary>Keybinding to launch 2nd dash app</summary>
<description>
Keybinding to launch 2nd app.
</description>
</key>
<key name="app-ctrl-hotkey-3" type="as">
<default><![CDATA[['<Ctrl><Super>3']]]></default>
<summary>Keybinding to launch 3rd dash app</summary>
<description>
Keybinding to launch 3rd app.
</description>
</key>
<key name="app-ctrl-hotkey-4" type="as">
<default><![CDATA[['<Ctrl><Super>4']]]></default>
<summary>Keybinding to launch 4th dash app</summary>
<description>
Keybinding to launch 4th app.
</description>
</key>
<key name="app-ctrl-hotkey-5" type="as">
<default><![CDATA[['<Ctrl><Super>5']]]></default>
<summary>Keybinding to launch 5th dash app</summary>
<description>
Keybinding to launch 5th app.
</description>
</key>
<key name="app-ctrl-hotkey-6" type="as">
<default><![CDATA[['<Ctrl><Super>6']]]></default>
<summary>Keybinding to launch 6th dash app</summary>
<description>
Keybinding to launch 6th app.
</description>
</key>
<key name="app-ctrl-hotkey-7" type="as">
<default><![CDATA[['<Ctrl><Super>7']]]></default>
<summary>Keybinding to launch 7th dash app</summary>
<description>
Keybinding to launch 7th app.
</description>
</key>
<key name="app-ctrl-hotkey-8" type="as">
<default><![CDATA[['<Ctrl><Super>8']]]></default>
<summary>Keybinding to launch 8th dash app</summary>
<description>
Keybinding to launch 8th app.
</description>
</key>
<key name="app-ctrl-hotkey-9" type="as">
<default><![CDATA[['<Ctrl><Super>9']]]></default>
<summary>Keybinding to launch 9th dash app</summary>
<description>
Keybinding to launch 9th app.
</description>
</key>
<key name="app-ctrl-hotkey-10" type="as">
<default><![CDATA[['<Ctrl><Super>0']]]></default>
<summary>Keybinding to launch 10th dash app</summary>
<description>
Keybinding to launch 10th app.
</description>
</key>
<key name="app-shift-hotkey-1" type="as">
<default><![CDATA[['<Shift><Super>1']]]></default>
<summary>Keybinding to trigger 1st dash app with shift behavior</summary>
<description>
Keybinding to trigger 1st app with shift behavior.
</description>
</key>
<key name="app-shift-hotkey-2" type="as">
<default><![CDATA[['<Shift><Super>2']]]></default>
<summary>Keybinding to trigger 2nd dash app with shift behavior</summary>
<description>
Keybinding to trigger 2nd app with shift behavior.
</description>
</key>
<key name="app-shift-hotkey-3" type="as">
<default><![CDATA[['<Shift><Super>3']]]></default>
<summary>Keybinding to trigger 3rd dash app with shift behavior</summary>
<description>
Keybinding to trigger 3rd app with shift behavior.
</description>
</key>
<key name="app-shift-hotkey-4" type="as">
<default><![CDATA[['<Shift><Super>4']]]></default>
<summary>Keybinding to trigger 4th dash app with shift behavior</summary>
<description>
Keybinding to trigger 4th app with shift behavior.
</description>
</key>
<key name="app-shift-hotkey-5" type="as">
<default><![CDATA[['<Shift><Super>5']]]></default>
<summary>Keybinding to trigger 5th dash app with shift behavior</summary>
<description>
Keybinding to trigger 5th app with shift behavior.
</description>
</key>
<key name="app-shift-hotkey-6" type="as">
<default><![CDATA[['<Shift><Super>6']]]></default>
<summary>Keybinding to trigger 6th dash app with shift behavior</summary>
<description>
Keybinding to trigger 6th app with shift behavior.
</description>
</key>
<key name="app-shift-hotkey-7" type="as">
<default><![CDATA[['<Shift><Super>7']]]></default>
<summary>Keybinding to trigger 7th dash app with shift behavior</summary>
<description>
Keybinding to trigger 7th app with shift behavior.
</description>
</key>
<key name="app-shift-hotkey-8" type="as">
<default><![CDATA[['<Shift><Super>8']]]></default>
<summary>Keybinding to trigger 8th dash app with shift behavior</summary>
<description>
Keybinding to trigger 8th app with shift behavior.
</description>
</key>
<key name="app-shift-hotkey-9" type="as">
<default><![CDATA[['<Shift><Super>9']]]></default>
<summary>Keybinding to trigger 9th dash app with shift behavior</summary>
<description>
Keybinding to trigger 9th app with shift behavior.
</description>
</key>
<key name="app-shift-hotkey-10" type="as">
<default><![CDATA[['<Shift><Super>0']]]></default>
<summary>Keybinding to trigger 10th dash app with shift behavior</summary>
<description>
Keybinding to trigger 10th app with shift behavior.
</description>
</key>
<key name="app-hotkey-1" type="as">
<default><![CDATA[['<Super>1']]]></default>
<summary>Keybinding to trigger 1st dash app</summary>
<description>
Keybinding to either show or launch the 1st application in the dash.
</description>
</key>
<key name="app-hotkey-2" type="as">
<default><![CDATA[['<Super>2']]]></default>
<summary>Keybinding to trigger 2nd dash app</summary>
<description>
Keybinding to either show or launch the 2nd application in the dash.
</description>
</key>
<key name="app-hotkey-3" type="as">
<default><![CDATA[['<Super>3']]]></default>
<summary>Keybinding to trigger 3rd dash app</summary>
<description>
Keybinding to either show or launch the 3rd application in the dash.
</description>
</key>
<key name="app-hotkey-4" type="as">
<default><![CDATA[['<Super>4']]]></default>
<summary>Keybinding to trigger 4th dash app</summary>
<description>
Keybinding to either show or launch the 4th application in the dash.
</description>
</key>
<key name="app-hotkey-5" type="as">
<default><![CDATA[['<Super>5']]]></default>
<summary>Keybinding to trigger 5th dash app</summary>
<description>
Keybinding to either show or launch the 5th application in the dash.
</description>
</key>
<key name="app-hotkey-6" type="as">
<default><![CDATA[['<Super>6']]]></default>
<summary>Keybinding to trigger 6th dash app</summary>
<description>
Keybinding to either show or launch the 6th application in the dash.
</description>
</key>
<key name="app-hotkey-7" type="as">
<default><![CDATA[['<Super>7']]]></default>
<summary>Keybinding to trigger 7th dash app</summary>
<description>
Keybinding to either show or launch the 7th application in the dash.
</description>
</key>
<key name="app-hotkey-8" type="as">
<default><![CDATA[['<Super>8']]]></default>
<summary>Keybinding to trigger 8th dash app</summary>
<description>
Keybinding to either show or launch the 8th application in the dash.
</description>
</key>
<key name="app-hotkey-9" type="as">
<default><![CDATA[['<Super>9']]]></default>
<summary>Keybinding to trigger 9th dash app</summary>
<description>
Keybinding to either show or launch the 9th application in the dash.
</description>
</key>
<key name="app-hotkey-10" type="as">
<default><![CDATA[['<Super>0']]]></default>
<summary>Keybinding to trigger 10th dash app</summary>
<description>
Keybinding to either show or launch the 10th application in the dash.
</description>
</key>
<key name="app-ctrl-hotkey-kp-1" type="as">
<default><![CDATA[['<Ctrl><Super>KP_1']]]></default>
<summary>Keybinding to launch 1st dash app</summary>
<description>
Keybinding to launch 1st app.
</description>
</key>
<key name="app-ctrl-hotkey-kp-2" type="as">
<default><![CDATA[['<Ctrl><Super>KP_2']]]></default>
<summary>Keybinding to launch 2nd dash app</summary>
<description>
Keybinding to launch 2nd app.
</description>
</key>
<key name="app-ctrl-hotkey-kp-3" type="as">
<default><![CDATA[['<Ctrl><Super>KP_3']]]></default>
<summary>Keybinding to launch 3rd dash app</summary>
<description>
Keybinding to launch 3rd app.
</description>
</key>
<key name="app-ctrl-hotkey-kp-4" type="as">
<default><![CDATA[['<Ctrl><Super>KP_4']]]></default>
<summary>Keybinding to launch 4th dash app</summary>
<description>
Keybinding to launch 4th app.
</description>
</key>
<key name="app-ctrl-hotkey-kp-5" type="as">
<default><![CDATA[['<Ctrl><Super>KP_5']]]></default>
<summary>Keybinding to launch 5th dash app</summary>
<description>
Keybinding to launch 5th app.
</description>
</key>
<key name="app-ctrl-hotkey-kp-6" type="as">
<default><![CDATA[['<Ctrl><Super>KP_6']]]></default>
<summary>Keybinding to launch 6th dash app</summary>
<description>
Keybinding to launch 6th app.
</description>
</key>
<key name="app-ctrl-hotkey-kp-7" type="as">
<default><![CDATA[['<Ctrl><Super>KP_7']]]></default>
<summary>Keybinding to launch 7th dash app</summary>
<description>
Keybinding to launch 7th app.
</description>
</key>
<key name="app-ctrl-hotkey-kp-8" type="as">
<default><![CDATA[['<Ctrl><Super>KP_8']]]></default>
<summary>Keybinding to launch 8th dash app</summary>
<description>
Keybinding to launch 8th app.
</description>
</key>
<key name="app-ctrl-hotkey-kp-9" type="as">
<default><![CDATA[['<Ctrl><Super>KP_9']]]></default>
<summary>Keybinding to launch 9th dash app</summary>
<description>
Keybinding to launch 9th app.
</description>
</key>
<key name="app-ctrl-hotkey-kp-10" type="as">
<default><![CDATA[['<Ctrl><Super>KP_0']]]></default>
<summary>Keybinding to launch 10th dash app</summary>
<description>
Keybinding to launch 10th app.
</description>
</key>
<key name="app-shift-hotkey-kp-1" type="as">
<default><![CDATA[['<Shift><Super>KP_1']]]></default>
<summary>Keybinding to trigger 1st dash app with shift behavior</summary>
<description>
Keybinding to trigger 1st app with shift behavior.
</description>
</key>
<key name="app-shift-hotkey-kp-2" type="as">
<default><![CDATA[['<Shift><Super>KP_2']]]></default>
<summary>Keybinding to trigger 2nd dash app with shift behavior</summary>
<description>
Keybinding to trigger 2nd app with shift behavior.
</description>
</key>
<key name="app-shift-hotkey-kp-3" type="as">
<default><![CDATA[['<Shift><Super>KP_3']]]></default>
<summary>Keybinding to trigger 3rd dash app with shift behavior</summary>
<description>
Keybinding to trigger 3rd app with shift behavior.
</description>
</key>
<key name="app-shift-hotkey-kp-4" type="as">
<default><![CDATA[['<Shift><Super>KP_4']]]></default>
<summary>Keybinding to trigger 4th dash app with shift behavior</summary>
<description>
Keybinding to trigger 4th app with shift behavior.
</description>
</key>
<key name="app-shift-hotkey-kp-5" type="as">
<default><![CDATA[['<Shift><Super>KP_5']]]></default>
<summary>Keybinding to trigger 5th dash app with shift behavior</summary>
<description>
Keybinding to trigger 5th app with shift behavior.
</description>
</key>
<key name="app-shift-hotkey-kp-6" type="as">
<default><![CDATA[['<Shift><Super>KP_6']]]></default>
<summary>Keybinding to trigger 6th dash app with shift behavior</summary>
<description>
Keybinding to trigger 6th app with shift behavior.
</description>
</key>
<key name="app-shift-hotkey-kp-7" type="as">
<default><![CDATA[['<Shift><Super>KP_7']]]></default>
<summary>Keybinding to trigger 7th dash app with shift behavior</summary>
<description>
Keybinding to trigger 7th app with shift behavior.
</description>
</key>
<key name="app-shift-hotkey-kp-8" type="as">
<default><![CDATA[['<Shift><Super>KP_8']]]></default>
<summary>Keybinding to trigger 8th dash app with shift behavior</summary>
<description>
Keybinding to trigger 8th app with shift behavior.
</description>
</key>
<key name="app-shift-hotkey-kp-9" type="as">
<default><![CDATA[['<Shift><Super>KP_9']]]></default>
<summary>Keybinding to trigger 9th dash app with shift behavior</summary>
<description>
Keybinding to trigger 9th app with shift behavior.
</description>
</key>
<key name="app-shift-hotkey-kp-10" type="as">
<default><![CDATA[['<Shift><Super>KP_0']]]></default>
<summary>Keybinding to trigger 10th dash app with shift behavior</summary>
<description>
Keybinding to trigger 10th app with shift behavior.
</description>
</key>
<key name="app-hotkey-kp-1" type="as">
<default><![CDATA[['<Super>KP_1']]]></default>
<summary>Keybinding to trigger 1st dash app</summary>
<description>
Keybinding to either show or launch the 1st application in the dash.
</description>
</key>
<key name="app-hotkey-kp-2" type="as">
<default><![CDATA[['<Super>KP_2']]]></default>
<summary>Keybinding to trigger 2nd dash app</summary>
<description>
Keybinding to either show or launch the 2nd application in the dash.
</description>
</key>
<key name="app-hotkey-kp-3" type="as">
<default><![CDATA[['<Super>KP_3']]]></default>
<summary>Keybinding to trigger 3rd dash app</summary>
<description>
Keybinding to either show or launch the 3rd application in the dash.
</description>
</key>
<key name="app-hotkey-kp-4" type="as">
<default><![CDATA[['<Super>KP_4']]]></default>
<summary>Keybinding to trigger 4th dash app</summary>
<description>
Keybinding to either show or launch the 4th application in the dash.
</description>
</key>
<key name="app-hotkey-kp-5" type="as">
<default><![CDATA[['<Super>KP_5']]]></default>
<summary>Keybinding to trigger 5th dash app</summary>
<description>
Keybinding to either show or launch the 5th application in the dash.
</description>
</key>
<key name="app-hotkey-kp-6" type="as">
<default><![CDATA[['<Super>KP_6']]]></default>
<summary>Keybinding to trigger 6th dash app</summary>
<description>
Keybinding to either show or launch the 6th application in the dash.
</description>
</key>
<key name="app-hotkey-kp-7" type="as">
<default><![CDATA[['<Super>KP_7']]]></default>
<summary>Keybinding to trigger 7th dash app</summary>
<description>
Keybinding to either show or launch the 7th application in the dash.
</description>
</key>
<key name="app-hotkey-kp-8" type="as">
<default><![CDATA[['<Super>KP_8']]]></default>
<summary>Keybinding to trigger 8th dash app</summary>
<description>
Keybinding to either show or launch the 8th application in the dash.
</description>
</key>
<key name="app-hotkey-kp-9" type="as">
<default><![CDATA[['<Super>KP_9']]]></default>
<summary>Keybinding to trigger 9th dash app</summary>
<description>
Keybinding to either show or launch the 9th application in the dash.
</description>
</key>
<key name="app-hotkey-kp-10" type="as">
<default><![CDATA[['<Super>KP_0']]]></default>
<summary>Keybinding to trigger 10th dash app</summary>
<description>
Keybinding to either show or launch the 10th application in the dash.
</description>
</key>
</schema>
</schemalist>
/*
* This file is part of the Dash-To-Panel extension for Gnome 3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
* Credits:
* This file is based on code from the Dash to Dock extension by micheleg
* and code from the Taskbar extension by Zorin OS
* Some code was also adapted from the upstream Gnome Shell source code.
*/
#dashtopanelTaskbar .dash-item-container > StWidget {
margin: 0;
padding: 0;
}
#dashtopanelScrollview .app-well-app .overview-icon,
#dashtopanelTaskbar .show-apps .overview-icon {
border: none;
margin: 0;
padding: 0;
}
#dashtopanelScrollview .app-well-app .overview-label {
padding-right: 8px;
}
#dashtopanelScrollview .app-well-app:hover .overview-icon,
#dashtopanelScrollview .app-well-app:focus .overview-icon {
background: none;
}
#dashtopanelScrollview .app-well-app:hover .dtp-container,
#dashtopanelScrollview .app-well-app:focus .dtp-container {
background-color: rgba(238, 238, 236, 0.1);
}
#dashtopanelScrollview .app-well-app:active .dtp-container {
background-color: rgba(238, 238, 236, 0.18);
}
#dashtopanelScrollview .app-well-app .favorite {
background-color: rgba(80, 150, 255, 0.4);
}
#dashtopanelScrollview .app-well-app-running-dot {
margin-bottom: 0;
}
#dashtopanelTaskbar .scrollview-fade {
background-gradient-end: rgba(0, 0, 0, 0);
}
.dashtopanelSecondaryMenu {
max-width: 400px;
}
.dashtopanelMainPanel.vertical .panel-button {
text-align: center;
}
.dashtopanelMainPanel.vertical .panel-button.vertical *,
.dashtopanelMainPanel.vertical .panel-button.clock-display * {
padding: 1px 0;
margin: 0;
}
.dashtopanelMainPanel.vertical .panel-button > *,
.dashtopanelMainPanel.vertical .panel-button.vertical > *,
.dashtopanelMainPanel.vertical .panel-button.clock-display > * {
padding: 8px 0;
}
#dashtopanelThumbnailList {
spacing: 0em;
padding: 0 1em;
}
#dashtopanelThumbnailList .popup-menu-item {
padding: 0;
border-radius: 5px;
spacing: 0;
}
#dashtopanelThumbnailList .window-box {
padding: 0;
spacing: 0;
}
#dashtopanelThumbnailList .preview-window-title {
padding-top: 1em;
}
.popup-menu.panel-menu {
margin-bottom: 0;
}
#panel #panelLeft, #panel #panelCenter {
spacing: 0px;
}
.showdesktop-button {
border: 0 solid rgba(200, 200, 200, .2);
}
.showdesktop-button-hovered {
background-color: rgba(200, 200, 200, .4);
}
.panel-corner:active, .panel-corner:overview, .panel-corner:focus {
-panel-corner-border-color: rgba(0, 0, 0, .001);
}
.number-overlay {
background-color: rgba(0,0,0,0.8);
color: rgba(256, 256, 256, 1);
text-align: center;
}
\ No newline at end of file
/*
* This file is part of the Dash-To-Panel extension for Gnome 3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
* Credits:
* This file is based on code from the Dash to Dock extension by micheleg
* and code from the Taskbar extension by Zorin OS
* Some code was also adapted from the upstream Gnome Shell source code.
*/
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
const Signals = imports.signals;
const Lang = imports.lang;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Mainloop = imports.mainloop;
const AppDisplay = imports.ui.appDisplay;
const AppFavorites = imports.ui.appFavorites;
const Dash = imports.ui.dash;
const DND = imports.ui.dnd;
const IconGrid = imports.ui.iconGrid;
const Main = imports.ui.main;
const PopupMenu = imports.ui.popupMenu;
const Tweener = imports.ui.tweener;
const Workspace = imports.ui.workspace;
const Me = imports.misc.extensionUtils.getCurrentExtension();
const AppIcons = Me.imports.appIcons;
const Panel = Me.imports.panel;
const Utils = Me.imports.utils;
const WindowPreview = Me.imports.windowPreview;
var DASH_ANIMATION_TIME = Dash.DASH_ANIMATION_TIME / (Dash.DASH_ANIMATION_TIME > 1 ? 1000 : 1);
var DASH_ITEM_HOVER_TIMEOUT = Dash.DASH_ITEM_HOVER_TIMEOUT;
var MIN_ICON_SIZE = 4;
/**
* Extend DashItemContainer
*
* - set label position based on taskbar orientation
*
* I can't subclass the original object because of this: https://bugzilla.gnome.org/show_bug.cgi?id=688973.
* thus use this ugly pattern.
*/
function extendDashItemContainer(dashItemContainer) {
dashItemContainer.showLabel = AppIcons.ItemShowLabel;
};
/* This class is a fork of the upstream DashActor class (ui.dash.js)
*
* Summary of changes:
* - modified chldBox calculations for when 'show-apps-at-top' option is checked
* - handle horizontal dash
*/
var taskbarActor = Utils.defineClass({
Name: 'DashToPanel-TaskbarActor',
Extends: St.Widget,
_init: function(delegate) {
this._delegate = delegate;
this._currentBackgroundColor = 0;
this.callParent('_init', { name: 'dashtopanelTaskbar',
layout_manager: new Clutter.BoxLayout({ orientation: Clutter.Orientation[Panel.getOrientation().toUpperCase()] }),
clip_to_allocation: true });
},
vfunc_allocate: function(box, flags) {
this.set_allocation(box, flags);
let availSize = box[Panel.fixedCoord.c2] - box[Panel.fixedCoord.c1];
let [, showAppsButton, scrollview, leftFade, rightFade] = this.get_children();
let [, showAppsNatSize] = showAppsButton[Panel.sizeFunc](availSize);
let childBox = new Clutter.ActorBox();
let orientation = Panel.getOrientation().toLowerCase();
childBox[Panel.varCoord.c1] = box[Panel.varCoord.c1];
childBox[Panel.fixedCoord.c1] = box[Panel.fixedCoord.c1];
childBox[Panel.varCoord.c2] = box[Panel.varCoord.c1] + showAppsNatSize;
childBox[Panel.fixedCoord.c2] = box[Panel.fixedCoord.c2];
showAppsButton.allocate(childBox, flags);
childBox[Panel.varCoord.c1] = box[Panel.varCoord.c1] + showAppsNatSize;
childBox[Panel.varCoord.c2] = box[Panel.varCoord.c2];
scrollview.allocate(childBox, flags);
let [hvalue, , hupper, , , hpageSize] = scrollview[orientation[0] + 'scroll'].adjustment.get_values();
hupper = Math.floor(hupper);
scrollview._dtpFadeSize = hupper > hpageSize ? this._delegate.iconSize : 0;
if (this._delegate.panel.dynamicTransparency &&
this._currentBackgroundColor !== this._delegate.panel.dynamicTransparency.currentBackgroundColor) {
this._currentBackgroundColor = this._delegate.panel.dynamicTransparency.currentBackgroundColor;
let gradientStyle = 'background-gradient-start: ' + this._currentBackgroundColor +
'background-gradient-direction: ' + orientation;
leftFade.set_style(gradientStyle);
rightFade.set_style(gradientStyle);
}
childBox[Panel.varCoord.c1] = box[Panel.varCoord.c1] + showAppsNatSize;
childBox[Panel.varCoord.c2] = childBox[Panel.varCoord.c1] + (hvalue > 0 ? scrollview._dtpFadeSize : 0);
leftFade.allocate(childBox, flags);
childBox[Panel.varCoord.c1] = box[Panel.varCoord.c2] - (hvalue + hpageSize < hupper ? scrollview._dtpFadeSize : 0);
childBox[Panel.varCoord.c2] = box[Panel.varCoord.c2];
rightFade.allocate(childBox, flags);
},
// We want to request the natural size of all our children
// as our natural width, so we chain up to StWidget (which
// then calls BoxLayout)
vfunc_get_preferred_width: function(forHeight) {
let [, natWidth] = St.Widget.prototype.vfunc_get_preferred_width.call(this, forHeight);
return [0, natWidth];
},
vfunc_get_preferred_height: function(forWidth) {
let [, natHeight] = St.Widget.prototype.vfunc_get_preferred_height.call(this, forWidth);
return [0, natHeight];
},
});
/* This class is a fork of the upstream dash class (ui.dash.js)
*
* Summary of changes:
* - disconnect global signals adding a destroy method;
* - play animations even when not in overview mode
* - set a maximum icon size
* - show running and/or favorite applications
* - emit a custom signal when an app icon is added
* - Add scrollview
* Ensure actor is visible on keyfocus inside the scrollview
* - add 128px icon size, might be useful for hidpi display
* - Sync minimization application target position.
*/
var taskbar = Utils.defineClass({
Name: 'DashToPanel.Taskbar',
_init : function(panel) {
this.panel = panel;
// start at smallest size due to running indicator drawing area expanding but not shrinking
this.iconSize = 16;
this._shownInitially = false;
this._signalsHandler = new Utils.GlobalSignalsHandler();
this._showLabelTimeoutId = 0;
this._resetHoverTimeoutId = 0;
this._ensureAppIconVisibilityTimeoutId = 0;
this._labelShowing = false;
let isVertical = Panel.checkIfVertical();
this._box = new St.BoxLayout({ vertical: isVertical,
clip_to_allocation: false,
x_align: Clutter.ActorAlign.START,
y_align: Clutter.ActorAlign.START });
this._container = new taskbarActor(this);
this._scrollView = new St.ScrollView({ name: 'dashtopanelScrollview',
hscrollbar_policy: Gtk.PolicyType.NEVER,
vscrollbar_policy: Gtk.PolicyType.NEVER,
enable_mouse_scrolling: true });
this._scrollView.connect('scroll-event', Lang.bind(this, this._onScrollEvent ));
this._scrollView.add_actor(this._box);
// Create a wrapper around the real showAppsIcon in order to add a popupMenu.
this._showAppsIconWrapper = new AppIcons.ShowAppsIconWrapper();
this._showAppsIconWrapper.connect('menu-state-changed', Lang.bind(this, function(showAppsIconWrapper, opened) {
this._itemMenuStateChanged(showAppsIconWrapper, opened);
}));
// an instance of the showAppsIcon class is encapsulated in the wrapper
this._showAppsIcon = this._showAppsIconWrapper.realShowAppsIcon;
this.showAppsButton = this._showAppsIcon.toggleButton;
if (isVertical) {
this.showAppsButton.set_width(panel.geom.w);
}
this.showAppsButton.connect('notify::checked', Lang.bind(this, this._onShowAppsButtonToggled));
this.showAppsButton.checked = Main.overview.viewSelector._showAppsButton.checked;
this._showAppsIcon.childScale = 1;
this._showAppsIcon.childOpacity = 255;
this._showAppsIcon.icon.setIconSize(this.iconSize);
this._hookUpLabel(this._showAppsIcon, this._showAppsIconWrapper);
this._container.add_child(new St.Widget({ width: 0, reactive: false }));
this._container.add_actor(this._showAppsIcon);
this._container.add_actor(this._scrollView);
let fadeStyle = 'background-gradient-direction:' + Panel.getOrientation();
let fade1 = new St.Widget({ style_class: 'scrollview-fade', reactive: false });
let fade2 = new St.Widget({ style_class: 'scrollview-fade',
reactive: false,
pivot_point: new Clutter.Point({ x: .5, y: .5 }),
rotation_angle_z: 180 });
fade1.set_style(fadeStyle);
fade2.set_style(fadeStyle);
this._container.add_actor(fade1);
this._container.add_actor(fade2);
this.previewMenu = new WindowPreview.PreviewMenu(panel);
this.previewMenu.enable();
if (!Me.settings.get_boolean('show-show-apps-button'))
this.hideShowAppsButton();
let rtl = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL;
this.actor = new St.Bin({ child: this._container,
y_align: St.Align.START, x_align:rtl?St.Align.END:St.Align.START
});
// Update minimization animation target position on allocation of the
// container and on scrollview change.
this._box.connect('notify::allocation', Lang.bind(this, this._updateAppIcons));
let scrollViewAdjustment = this._scrollView.hscroll.adjustment;
scrollViewAdjustment.connect('notify::value', Lang.bind(this, this._updateAppIcons));
this._workId = Main.initializeDeferredWork(this._box, Lang.bind(this, this._redisplay));
this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell' });
this._appSystem = Shell.AppSystem.get_default();
this._signalsHandler.add(
[
this.panel,
'notify::height',
() => this._queueRedisplay()
],
[
this.panel,
'notify::width',
() => this._queueRedisplay()
],
[
this._appSystem,
'installed-changed',
Lang.bind(this, function() {
AppFavorites.getAppFavorites().reload();
this._queueRedisplay();
})
],
[
this._appSystem,
'app-state-changed',
Lang.bind(this, this._queueRedisplay)
],
[
AppFavorites.getAppFavorites(),
'changed',
Lang.bind(this, this._queueRedisplay)
],
[
global.window_manager,
'switch-workspace',
() => this._connectWorkspaceSignals()
],
[
Utils.DisplayWrapper.getScreen(),
[
'window-entered-monitor',
'window-left-monitor'
],
() => {
if (Me.settings.get_boolean('isolate-monitors')) {
this._queueRedisplay();
}
}
],
[
Main.overview,
'item-drag-begin',
Lang.bind(this, this._onDragBegin)
],
[
Main.overview,
'item-drag-end',
Lang.bind(this, this._onDragEnd)
],
[
Main.overview,
'item-drag-cancelled',
Lang.bind(this, this._onDragCancelled)
],
[
// Ensure the ShowAppsButton status is kept in sync
Main.overview.viewSelector._showAppsButton,
'notify::checked',
Lang.bind(this, this._syncShowAppsButtonToggled)
],
[
Me.settings,
'changed::show-show-apps-button',
Lang.bind(this, function() {
if (Me.settings.get_boolean('show-show-apps-button'))
this.showShowAppsButton();
else
this.hideShowAppsButton();
this.resetAppIcons();
})
],
[
Me.settings,
[
'changed::dot-size',
'changed::show-favorites',
'changed::show-running-apps',
'changed::show-favorites-all-monitors'
],
Lang.bind(this, this._redisplay)
],
[
Me.settings,
'changed::group-apps',
Lang.bind(this, function() {
this.isGroupApps = Me.settings.get_boolean('group-apps');
this._connectWorkspaceSignals();
this.resetAppIcons();
})
],
[
Me.settings,
[
'changed::group-apps-use-launchers',
'changed::taskbar-locked'
],
() => this.resetAppIcons()
]
);
this.isGroupApps = Me.settings.get_boolean('group-apps');
this._connectWorkspaceSignals();
},
destroy: function() {
this._signalsHandler.destroy();
this._signalsHandler = 0;
this._showAppsIconWrapper.destroy();
this._container.destroy();
this.previewMenu.disable();
this.previewMenu.destroy();
this._disconnectWorkspaceSignals();
},
_onScrollEvent: function(actor, event) {
// Event coordinates are relative to the stage but can be transformed
// as the actor will only receive events within his bounds.
let stage_x, stage_y, ok, event_x, event_y, actor_w, actor_h;
[stage_x, stage_y] = event.get_coords();
[ok, event_x, event_y] = actor.transform_stage_point(stage_x, stage_y);
[actor_w, actor_h] = actor.get_size();
// reset timeout to avid conflicts with the mousehover event
if (this._ensureAppIconVisibilityTimeoutId>0) {
Mainloop.source_remove(this._ensureAppIconVisibilityTimeoutId);
this._ensureAppIconVisibilityTimeoutId = 0;
}
// Skip to avoid double events mouse
if (event.is_pointer_emulated())
return Clutter.EVENT_STOP;
let adjustment, delta;
adjustment = this._scrollView.get_hscroll_bar().get_adjustment();
let increment = adjustment.step_increment;
switch ( event.get_scroll_direction() ) {
case Clutter.ScrollDirection.UP:
case Clutter.ScrollDirection.LEFT:
delta = -increment;
break;
case Clutter.ScrollDirection.DOWN:
case Clutter.ScrollDirection.RIGHT:
delta = +increment;
break;
case Clutter.ScrollDirection.SMOOTH:
let [dx, dy] = event.get_scroll_delta();
delta = dy*increment;
delta += dx*increment;
break;
}
adjustment.set_value(adjustment.get_value() + delta);
return Clutter.EVENT_STOP;
},
_onDragBegin: function() {
this._dragCancelled = false;
this._dragMonitor = {
dragMotion: Lang.bind(this, this._onDragMotion)
};
DND.addDragMonitor(this._dragMonitor);
if (this._box.get_n_children() == 0) {
this._emptyDropTarget = new Dash.EmptyDropTargetItem();
this._box.insert_child_at_index(this._emptyDropTarget, 0);
this._emptyDropTarget.show(true);
}
this._toggleFavortieHighlight(true);
},
_onDragCancelled: function() {
this._dragCancelled = true;
if (this._dragInfo) {
this._box.set_child_at_index(this._dragInfo[1]._dashItemContainer, this._dragInfo[0]);
}
this._endDrag();
},
_onDragEnd: function() {
if (this._dragCancelled)
return;
this._endDrag();
},
_endDrag: function() {
if (this._dragInfo && this._dragInfo[1]._dashItemContainer instanceof DragPlaceholderItem) {
this._box.remove_child(this._dragInfo[1]._dashItemContainer);
this._dragInfo[1]._dashItemContainer.destroy();
delete this._dragInfo[1]._dashItemContainer;
}
this._dragInfo = null;
this._clearEmptyDropTarget();
this._showAppsIcon.setDragApp(null);
DND.removeDragMonitor(this._dragMonitor);
this._toggleFavortieHighlight();
},
_onDragMotion: function(dragEvent) {
let app = Dash.getAppFromSource(dragEvent.source);
if (app == null)
return DND.DragMotionResult.CONTINUE;
let showAppsHovered = this._showAppsIcon.contains(dragEvent.targetActor);
if (showAppsHovered)
this._showAppsIcon.setDragApp(app);
else
this._showAppsIcon.setDragApp(null);
return DND.DragMotionResult.CONTINUE;
},
_toggleFavortieHighlight: function(show) {
let appFavorites = AppFavorites.getAppFavorites();
let cssFuncName = (show ? 'add' : 'remove') + '_style_class_name';
this._getAppIcons().filter(appIcon => appFavorites.isFavorite(appIcon.app.get_id()))
.forEach(fav => fav._container[cssFuncName]('favorite'));
},
handleIsolatedWorkspaceSwitch: function() {
this._shownInitially = this.isGroupApps;
this._queueRedisplay();
},
_connectWorkspaceSignals: function() {
this._disconnectWorkspaceSignals();
this._lastWorkspace = Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace();
this._workspaceWindowAddedId = this._lastWorkspace.connect('window-added', () => this._queueRedisplay());
this._workspaceWindowRemovedId = this._lastWorkspace.connect('window-removed', () => this._queueRedisplay());
},
_disconnectWorkspaceSignals: function() {
if (this._lastWorkspace) {
this._lastWorkspace.disconnect(this._workspaceWindowAddedId);
this._lastWorkspace.disconnect(this._workspaceWindowRemovedId);
this._lastWorkspace = null;
}
},
_queueRedisplay: function () {
Main.queueDeferredWork(this._workId);
},
_hookUpLabel: function(item, syncHandler) {
item.child.connect('notify::hover', Lang.bind(this, function() {
this._syncLabel(item, syncHandler);
}));
syncHandler.connect('sync-tooltip', Lang.bind(this, function() {
this._syncLabel(item, syncHandler);
}));
},
_createAppItem: function(app, window, isLauncher) {
let appIcon = new AppIcons.taskbarAppIcon(
{
app: app,
window: window,
isLauncher: isLauncher
},
this.panel,
{
setSizeManually: true,
showLabel: false,
isDraggable: !Me.settings.get_boolean('taskbar-locked'),
},
this.previewMenu
);
if (appIcon._draggable) {
appIcon._draggable.connect('drag-begin',
Lang.bind(this, function() {
appIcon.actor.opacity = 50;
}));
appIcon._draggable.connect('drag-end',
Lang.bind(this, function() {
appIcon.actor.opacity = 255;
}));
}
appIcon.connect('menu-state-changed',
Lang.bind(this, function(appIcon, opened) {
this._itemMenuStateChanged(item, opened);
}));
let item = new Dash.DashItemContainer();
extendDashItemContainer(item);
item.setChild(appIcon.actor);
appIcon._dashItemContainer = item;
appIcon.actor.connect('notify::hover', Lang.bind(this, function() {
if (appIcon.actor.hover){
this._ensureAppIconVisibilityTimeoutId = Mainloop.timeout_add(100, Lang.bind(this, function(){
Utils.ensureActorVisibleInScrollView(this._scrollView, appIcon.actor, this._scrollView._dtpFadeSize);
this._ensureAppIconVisibilityTimeoutId = 0;
return GLib.SOURCE_REMOVE;
}));
} else {
if (this._ensureAppIconVisibilityTimeoutId>0) {
Mainloop.source_remove(this._ensureAppIconVisibilityTimeoutId);
this._ensureAppIconVisibilityTimeoutId = 0;
}
}
}));
appIcon.actor.connect('clicked',
Lang.bind(this, function(actor) {
Utils.ensureActorVisibleInScrollView(this._scrollView, actor, this._scrollView._dtpFadeSize);
}));
appIcon.actor.connect('key-focus-in', Lang.bind(this, function(actor) {
let [x_shift, y_shift] = Utils.ensureActorVisibleInScrollView(this._scrollView, actor, this._scrollView._dtpFadeSize);
// This signal is triggered also by mouse click. The popup menu is opened at the original
// coordinates. Thus correct for the shift which is going to be applied to the scrollview.
if (appIcon._menu) {
appIcon._menu._boxPointer.xOffset = -x_shift;
appIcon._menu._boxPointer.yOffset = -y_shift;
}
}));
// Override default AppIcon label_actor, now the
// accessible_name is set at DashItemContainer.setLabelText
appIcon.actor.label_actor = null;
item.setLabelText(app.get_name());
appIcon.icon.setIconSize(this.iconSize);
this._hookUpLabel(item, appIcon);
return item;
},
// Return an array with the "proper" appIcons currently in the taskbar
_getAppIcons: function() {
// Only consider children which are "proper" icons and which are not
// animating out (which means they will be destroyed at the end of
// the animation)
return this._getTaskbarIcons().map(function(actor){
return actor.child._delegate;
});
},
_getTaskbarIcons: function(includeAnimated) {
return this._box.get_children().filter(function(actor) {
return actor.child &&
actor.child._delegate &&
actor.child._delegate.icon &&
(includeAnimated || !actor.animatingOut);
});
},
_updateAppIcons: function() {
let appIcons = this._getAppIcons();
appIcons.filter(icon => icon.constructor === AppIcons.taskbarAppIcon).forEach(icon => {
icon.updateIcon();
});
},
_itemMenuStateChanged: function(item, opened) {
// When the menu closes, it calls sync_hover, which means
// that the notify::hover handler does everything we need to.
if (opened) {
if (this._showLabelTimeoutId > 0) {
Mainloop.source_remove(this._showLabelTimeoutId);
this._showLabelTimeoutId = 0;
}
item.hideLabel();
} else {
// I want to listen from outside when a menu is closed. I used to
// add a custom signal to the appIcon, since gnome 3.8 the signal
// calling this callback was added upstream.
this.emit('menu-closed');
}
},
_syncLabel: function (item, syncHandler) {
let shouldShow = syncHandler ? syncHandler.shouldShowTooltip() : item.child.get_hover();
if (shouldShow) {
if (this._showLabelTimeoutId == 0) {
let timeout = this._labelShowing ? 0 : DASH_ITEM_HOVER_TIMEOUT;
this._showLabelTimeoutId = Mainloop.timeout_add(timeout,
Lang.bind(this, function() {
this._labelShowing = true;
item.showLabel();
this._showLabelTimeoutId = 0;
return GLib.SOURCE_REMOVE;
}));
GLib.Source.set_name_by_id(this._showLabelTimeoutId, '[gnome-shell] item.showLabel');
if (this._resetHoverTimeoutId > 0) {
Mainloop.source_remove(this._resetHoverTimeoutId);
this._resetHoverTimeoutId = 0;
}
}
} else {
if (this._showLabelTimeoutId > 0)
Mainloop.source_remove(this._showLabelTimeoutId);
this._showLabelTimeoutId = 0;
item.hideLabel();
if (this._labelShowing) {
this._resetHoverTimeoutId = Mainloop.timeout_add(DASH_ITEM_HOVER_TIMEOUT,
Lang.bind(this, function() {
this._labelShowing = false;
this._resetHoverTimeoutId = 0;
return GLib.SOURCE_REMOVE;
}));
GLib.Source.set_name_by_id(this._resetHoverTimeoutId, '[gnome-shell] this._labelShowing');
}
}
},
_adjustIconSize: function() {
let panelSize = Me.settings.get_int('panel-size');
let availSize = panelSize - Me.settings.get_int('appicon-padding') * 2;
let minIconSize = MIN_ICON_SIZE + panelSize % 2;
if (availSize == this.iconSize)
return;
if (availSize < minIconSize) {
availSize = minIconSize;
}
// For the icon size, we only consider children which are "proper"
// icons and which are not animating out (which means they will be
// destroyed at the end of the animation)
let iconChildren = this._getTaskbarIcons().concat([this._showAppsIcon]);
let scale = this.iconSize / availSize;
this.iconSize = availSize;
this.emit('icon-size-changed');
for (let i = 0; i < iconChildren.length; i++) {
let icon = iconChildren[i].child._delegate.icon;
// Set the new size immediately, to keep the icons' sizes
// in sync with this.iconSize
icon.setIconSize(this.iconSize);
// Don't animate the icon size change when the overview
// is transitioning, or when initially filling
// the taskbar
if (Main.overview.animationInProgress ||
!this._shownInitially)
continue;
let [targetWidth, targetHeight] = icon.icon.get_size();
// Scale the icon's texture to the previous size and
// tween to the new size
icon.icon.set_size(icon.icon.width * scale, icon.icon.height * scale);
Tweener.addTween(icon.icon,
{ width: targetWidth,
height: targetHeight,
time: DASH_ANIMATION_TIME,
transition: 'easeOutQuad',
});
}
},
sortAppsCompareFunction: function(appA, appB) {
return getAppStableSequence(appA, this.panel.monitor) -
getAppStableSequence(appB, this.panel.monitor);
},
getAppInfos: function() {
//get the user's favorite apps
let favoriteApps = this._checkIfShowingFavorites() ? AppFavorites.getAppFavorites().getFavorites() : [];
//find the apps that should be in the taskbar: the favorites first, then add the running apps
// When using isolation, we filter out apps that have no windows in
// the current workspace (this check is done in AppIcons.getInterestingWindows)
let runningApps = this._checkIfShowingRunningApps() ? this._getRunningApps().sort(this.sortAppsCompareFunction.bind(this)) : [];
if (!this.isGroupApps && Me.settings.get_boolean('group-apps-use-launchers')) {
return this._createAppInfos(favoriteApps, [], true)
.concat(this._createAppInfos(runningApps)
.filter(appInfo => appInfo.windows.length));
} else {
return this._createAppInfos(favoriteApps.concat(runningApps.filter(app => favoriteApps.indexOf(app) < 0)))
.filter(appInfo => appInfo.windows.length || favoriteApps.indexOf(appInfo.app) >= 0);
}
},
_redisplay: function () {
if (!this._signalsHandler) {
return;
}
//get the currently displayed appIcons
let currentAppIcons = this._getTaskbarIcons();
let expectedAppInfos = this.getAppInfos();
//remove the appIcons which are not in the expected apps list
for (let i = currentAppIcons.length - 1; i > -1; --i) {
let appIcon = currentAppIcons[i].child._delegate;
let appIndex = Utils.findIndex(expectedAppInfos, appInfo => appInfo.app == appIcon.app &&
appInfo.isLauncher == appIcon.isLauncher);
if (appIndex < 0 ||
(appIcon.window && (this.isGroupApps || expectedAppInfos[appIndex].windows.indexOf(appIcon.window) < 0)) ||
(!appIcon.window && !appIcon.isLauncher &&
!this.isGroupApps && expectedAppInfos[appIndex].windows.length)) {
currentAppIcons[i][this._shownInitially ? 'animateOutAndDestroy' : 'destroy']();
currentAppIcons.splice(i, 1);
}
}
//if needed, reorder the existing appIcons and create the missing ones
let currentPosition = 0;
for (let i = 0, l = expectedAppInfos.length; i < l; ++i) {
let neededAppIcons = this.isGroupApps || !expectedAppInfos[i].windows.length ?
[{ app: expectedAppInfos[i].app, window: null, isLauncher: expectedAppInfos[i].isLauncher }] :
expectedAppInfos[i].windows.map(window => ({ app: expectedAppInfos[i].app, window: window, isLauncher: false }));
for (let j = 0, ll = neededAppIcons.length; j < ll; ++j) {
//check if the icon already exists
let matchingAppIconIndex = Utils.findIndex(currentAppIcons, appIcon => appIcon.child._delegate.app == neededAppIcons[j].app &&
appIcon.child._delegate.window == neededAppIcons[j].window);
if (matchingAppIconIndex > 0 && matchingAppIconIndex != currentPosition) {
//moved icon, reposition it
this._box.remove_child(currentAppIcons[matchingAppIconIndex]);
this._box.insert_child_at_index(currentAppIcons[matchingAppIconIndex], currentPosition);
} else if (matchingAppIconIndex < 0) {
//the icon doesn't exist yet, create a new one
let newAppIcon = this._createAppItem(neededAppIcons[j].app, neededAppIcons[j].window, neededAppIcons[j].isLauncher);
this._box.insert_child_at_index(newAppIcon, currentPosition);
currentAppIcons.splice(currentPosition, 0, newAppIcon);
// Skip animations on first run when adding the initial set
// of items, to avoid all items zooming in at once
newAppIcon.show(this._shownInitially);
}
++currentPosition;
}
}
this._adjustIconSize();
// Workaround for https://bugzilla.gnome.org/show_bug.cgi?id=692744
// Without it, StBoxLayout may use a stale size cache
this._box.queue_relayout();
// This is required for icon reordering when the scrollview is used.
this._updateAppIcons();
// This will update the size, and the corresponding number for each icon on the primary panel
if (!this.panel.isSecondary) {
this._updateNumberOverlay();
}
this._shownInitially = true;
},
_checkIfShowingRunningApps: function() {
return Me.settings.get_boolean('show-running-apps');
},
_checkIfShowingFavorites: function() {
return Me.settings.get_boolean('show-favorites') &&
(!this.panel.isSecondary || Me.settings.get_boolean('show-favorites-all-monitors'));
},
_getRunningApps: function() {
let tracker = Shell.WindowTracker.get_default();
let windows = global.get_window_actors();
let apps = [];
for (let i = 0, l = windows.length; i < l; ++i) {
let app = tracker.get_window_app(windows[i].metaWindow);
if (app && apps.indexOf(app) < 0) {
apps.push(app);
}
}
return apps;
},
_createAppInfos: function(apps, defaultWindows, defaultIsLauncher) {
return apps.map(app => ({
app: app,
isLauncher: defaultIsLauncher || false,
windows: defaultWindows || AppIcons.getInterestingWindows(app, this.panel.monitor)
.sort(sortWindowsCompareFunction)
}));
},
// Reset the displayed apps icon to mantain the correct order
resetAppIcons : function() {
let children = this._getTaskbarIcons(true);
for (let i = 0; i < children.length; i++) {
let item = children[i];
item.destroy();
}
// to avoid ugly animations, just suppress them like when taskbar is first loaded.
this._shownInitially = false;
this._redisplay();
if (Panel.checkIfVertical()) {
this.showAppsButton.set_width(this.panel.geom.w);
this.previewMenu._updateClip();
}
},
_updateNumberOverlay: function() {
let seenApps = {};
let counter = 0;
this._getAppIcons().forEach(function(icon) {
if (!seenApps[icon.app]) {
seenApps[icon.app] = 1;
counter++;
}
if (counter <= 10) {
icon.setNumberOverlay(counter == 10 ? 0 : counter);
} else {
// No overlay after 10
icon.setNumberOverlay(-1);
}
icon.updateNumberOverlay();
});
if (Me.settings.get_boolean('hot-keys') &&
Me.settings.get_string('hotkeys-overlay-combo') === 'ALWAYS')
this.toggleNumberOverlay(true);
},
toggleNumberOverlay: function(activate) {
let appIcons = this._getAppIcons();
appIcons.forEach(function(icon) {
icon.toggleNumberOverlay(activate);
});
},
_clearEmptyDropTarget: function() {
if (this._emptyDropTarget) {
this._emptyDropTarget.animateOutAndDestroy();
this._emptyDropTarget = null;
}
},
handleDragOver: function(source, actor, x, y, time) {
if (source == Main.xdndHandler)
return DND.DragMotionResult.CONTINUE;
// Don't allow favoriting of transient apps
if (source.app == null || source.app.is_window_backed())
return DND.DragMotionResult.NO_DROP;
if (!this._settings.is_writable('favorite-apps'))
return DND.DragMotionResult.NO_DROP;
if (!this._box.contains(source.actor) && !source._dashItemContainer) {
//not an appIcon of the taskbar, probably from the applications view
source._dashItemContainer = new DragPlaceholderItem(source, this.iconSize);
this._box.insert_child_above(source._dashItemContainer, null);
}
let isVertical = Panel.checkIfVertical();
let sizeProp = isVertical ? 'height' : 'width';
let posProp = isVertical ? 'y' : 'x';
let pos = isVertical ? y : x;
pos -= this.showAppsButton[sizeProp];
let currentAppIcons = this._getAppIcons();
let sourceIndex = currentAppIcons.indexOf(source);
let hoveredIndex = Utils.findIndex(currentAppIcons,
appIcon => pos >= appIcon._dashItemContainer[posProp] &&
pos <= (appIcon._dashItemContainer[posProp] + appIcon._dashItemContainer[sizeProp]));
if (!this._dragInfo) {
this._dragInfo = [sourceIndex, source];
}
if (hoveredIndex >= 0) {
let isLeft = pos < currentAppIcons[hoveredIndex]._dashItemContainer[posProp] + currentAppIcons[hoveredIndex]._dashItemContainer[sizeProp] * .5;
// Don't allow positioning before or after self and between icons of same app
if (!(hoveredIndex === sourceIndex ||
(isLeft && hoveredIndex - 1 == sourceIndex) ||
(isLeft && hoveredIndex - 1 >= 0 && source.app != currentAppIcons[hoveredIndex - 1].app &&
currentAppIcons[hoveredIndex - 1].app == currentAppIcons[hoveredIndex].app) ||
(!isLeft && hoveredIndex + 1 == sourceIndex) ||
(!isLeft && hoveredIndex + 1 < currentAppIcons.length && source.app != currentAppIcons[hoveredIndex + 1].app &&
currentAppIcons[hoveredIndex + 1].app == currentAppIcons[hoveredIndex].app))) {
this._box.set_child_at_index(source._dashItemContainer, hoveredIndex);
// Ensure the next and previous icon are visible when moving the icon
// (I assume there's room for both of them)
if (hoveredIndex > 1)
Utils.ensureActorVisibleInScrollView(this._scrollView, this._box.get_children()[hoveredIndex-1], this._scrollView._dtpFadeSize);
if (hoveredIndex < this._box.get_children().length-1)
Utils.ensureActorVisibleInScrollView(this._scrollView, this._box.get_children()[hoveredIndex+1], this._scrollView._dtpFadeSize);
}
}
return this._dragInfo[0] !== sourceIndex ? DND.DragMotionResult.MOVE_DROP : DND.DragMotionResult.CONTINUE;
},
// Draggable target interface
acceptDrop : function(source, actor, x, y, time) {
// Don't allow favoriting of transient apps
if (!source.app || source.app.is_window_backed() || !this._settings.is_writable('favorite-apps')) {
return false;
}
let appIcons = this._getAppIcons();
let sourceIndex = appIcons.indexOf(source);
let usingLaunchers = !this.isGroupApps && Me.settings.get_boolean('group-apps-use-launchers');
// dragging the icon to its original position
if (this._dragInfo[0] === sourceIndex) {
return true;
}
let appFavorites = AppFavorites.getAppFavorites();
let sourceAppId = source.app.get_id();
let appIsFavorite = appFavorites.isFavorite(sourceAppId);
let replacingIndex = sourceIndex + (sourceIndex > this._dragInfo[0] ? -1 : 1);
let favoriteIndex = replacingIndex >= 0 ? appFavorites.getFavorites().indexOf(appIcons[replacingIndex].app) : 0;
let sameApps = appIcons.filter(a => a != source && a.app == source.app);
let showingFavorites = this._checkIfShowingFavorites();
let favoritesCount = 0;
let position = 0;
let interestingWindows = {};
let getAppWindows = app => {
if (!interestingWindows[app]) {
interestingWindows[app] = AppIcons.getInterestingWindows(app, this.panel.monitor);
}
let appWindows = interestingWindows[app]; //prevents "reference to undefined property Symbol.toPrimitive" warning
return appWindows;
};
if (sameApps.length &&
((!appIcons[sourceIndex - 1] || appIcons[sourceIndex - 1].app !== source.app) &&
(!appIcons[sourceIndex + 1] || appIcons[sourceIndex + 1].app !== source.app))) {
appIcons.splice(appIcons.indexOf(sameApps[0]), sameApps.length);
Array.prototype.splice.apply(appIcons, [sourceIndex + 1, 0].concat(sameApps));
}
for (let i = 0, l = appIcons.length; i < l; ++i) {
let windows = [];
if (!usingLaunchers || (!source.isLauncher && !appIcons[i].isLauncher)) {
windows = appIcons[i].window ? [appIcons[i].window] : getAppWindows(appIcons[i].app);
}
windows.forEach(w => w._dtpPosition = position++);
if (showingFavorites &&
((usingLaunchers && appIcons[i].isLauncher) ||
(!usingLaunchers && appFavorites.isFavorite(appIcons[i].app.get_id())))) {
++favoritesCount;
}
}
if (sourceIndex < favoritesCount) {
if (appIsFavorite) {
appFavorites.moveFavoriteToPos(sourceAppId, favoriteIndex);
} else {
appFavorites.addFavoriteAtPos(sourceAppId, favoriteIndex);
}
} else if (appIsFavorite && showingFavorites && (!usingLaunchers || source.isLauncher)) {
appFavorites.removeFavorite(sourceAppId);
}
appFavorites.emit('changed');
return true;
},
_onShowAppsButtonToggled: function() {
// Sync the status of the default appButtons. Only if the two statuses are
// different, that means the user interacted with the extension provided
// application button, cutomize the behaviour. Otherwise the shell has changed the
// status (due to the _syncShowAppsButtonToggled function below) and it
// has already performed the desired action.
let animate = Me.settings.get_boolean('animate-show-apps');
let selector = Main.overview.viewSelector;
if (selector._showAppsButton.checked !== this.showAppsButton.checked) {
// find visible view
let visibleView;
Main.overview.viewSelector.appDisplay._views.every(function(v, index) {
if (v.view.actor.visible) {
visibleView = index;
return false;
}
else
return true;
});
if (this.showAppsButton.checked) {
// force spring animation triggering.By default the animation only
// runs if we are already inside the overview.
if (!Main.overview._shown) {
this.forcedOverview = true;
let view = Main.overview.viewSelector.appDisplay._views[visibleView].view;
let grid = view._grid;
if (animate) {
// Animate in the the appview, hide the appGrid to avoiud flashing
// Go to the appView before entering the overview, skipping the workspaces.
// Do this manually avoiding opacity in transitions so that the setting of the opacity
// to 0 doesn't get overwritten.
Main.overview.viewSelector._activePage.opacity = 0;
Main.overview.viewSelector._activePage.hide();
Main.overview.viewSelector._activePage = Main.overview.viewSelector._appsPage;
Main.overview.viewSelector._activePage.show();
grid.actor.opacity = 0;
// The animation has to be trigered manually because the AppDisplay.animate
// method is waiting for an allocation not happening, as we skip the workspace view
// and the appgrid could already be allocated from previous shown.
// It has to be triggered after the overview is shown as wrong coordinates are obtained
// otherwise.
let overviewShownId = Main.overview.connect('shown', Lang.bind(this, function() {
Main.overview.disconnect(overviewShownId);
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
grid.actor.opacity = 255;
grid.animateSpring(IconGrid.AnimationDirection.IN, this.showAppsButton);
}));
}));
} else {
Main.overview.viewSelector._activePage = Main.overview.viewSelector._appsPage;
Main.overview.viewSelector._activePage.show();
grid.actor.opacity = 255;
}
}
//temporarily use as primary the monitor on which the showapps btn was clicked
this.panel.panelManager.setFocusedMonitor(this.panel.monitor);
//reset the primary monitor when exiting the overview
let overviewHiddenId = Main.overview.connect('hidden', () => {
Main.overview.disconnect(overviewHiddenId);
this.panel.panelManager.setFocusedMonitor(this.panel.panelManager.primaryPanel.monitor, true);
});
// Finally show the overview
selector._showAppsButton.checked = true;
Main.overview.show();
}
else {
if (this.forcedOverview) {
// force exiting overview if needed
if (animate) {
// Manually trigger springout animation without activating the
// workspaceView to avoid the zoomout animation. Hide the appPage
// onComplete to avoid ugly flashing of original icons.
let view = Main.overview.viewSelector.appDisplay._views[visibleView].view;
view.animate(IconGrid.AnimationDirection.OUT, Lang.bind(this, function() {
Main.overview.viewSelector._appsPage.hide();
Main.overview.hide();
selector._showAppsButton.checked = false;
this.forcedOverview = false;
}));
}
else {
Main.overview.hide();
this.forcedOverview = false;
}
}
else {
selector._showAppsButton.checked = false;
this.forcedOverview = false;
}
}
}
},
_syncShowAppsButtonToggled: function() {
let status = Main.overview.viewSelector._showAppsButton.checked;
if (this.showAppsButton.checked !== status)
this.showAppsButton.checked = status;
},
showShowAppsButton: function() {
this.showAppsButton.visible = true;
this.showAppsButton.set_width(-1);
this.showAppsButton.set_height(-1);
},
hideShowAppsButton: function() {
this.showAppsButton.hide();
this.showAppsButton.set_width(0);
this.showAppsButton.set_height(0);
},
popupFocusedAppSecondaryMenu: function() {
let appIcons = this._getAppIcons();
for(let i in appIcons) {
if(appIcons[i].app == tracker.focus_app) {
let appIcon = appIcons[i];
if(appIcon._menu && appIcon._menu.isOpen)
appIcon._menu.close();
else
appIcons[i].popupMenu();
break;
}
}
},
});
Signals.addSignalMethods(taskbar.prototype);
var DragPlaceholderItem = Utils.defineClass({
Name: 'DashToPanel-DragPlaceholderItem',
Extends: St.Widget,
_init: function(appIcon, iconSize) {
this.callParent('_init', { style: AppIcons.getIconContainerStyle(), layout_manager: new Clutter.BinLayout() });
this.child = { _delegate: appIcon };
this._clone = new Clutter.Clone({
source: appIcon.icon._iconBin,
width: iconSize,
height: iconSize
});
this.add_actor(this._clone);
},
destroy: function() {
this._clone.destroy();
this.callParent('destroy');
},
});
function getAppStableSequence(app, monitor) {
let windows = AppIcons.getInterestingWindows(app, monitor);
return windows.reduce((prevWindow, window) => {
return Math.min(prevWindow, getWindowStableSequence(window));
}, Infinity);
}
function sortWindowsCompareFunction(windowA, windowB) {
return getWindowStableSequence(windowA) - getWindowStableSequence(windowB);
}
function getWindowStableSequence(window) {
return ('_dtpPosition' in window ? window._dtpPosition : window.get_stable_sequence());
}
/*
* This file is part of the Dash-To-Panel extension for Gnome 3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
const Clutter = imports.gi.Clutter;
const GdkPixbuf = imports.gi.GdkPixbuf;
const Lang = imports.lang;
const Main = imports.ui.main;
const Meta = imports.gi.Meta;
const St = imports.gi.St;
const Me = imports.misc.extensionUtils.getCurrentExtension();
const Panel = Me.imports.panel;
const Proximity = Me.imports.proximity;
const Utils = Me.imports.utils;
var DynamicTransparency = Utils.defineClass({
Name: 'DashToPanel.DynamicTransparency',
_init: function(dtpPanel) {
this._dtpPanel = dtpPanel;
this._proximityManager = dtpPanel.panelManager.proximityManager;
this._proximityWatchId = 0;
this._windowOverlap = false;
this.currentBackgroundColor = 0;
this._initialPanelStyle = dtpPanel.get_style();
if (this._dtpPanel._leftCorner) {
this._initialPanelCornerStyle = dtpPanel._leftCorner.actor.get_style();
}
this._signalsHandler = new Utils.GlobalSignalsHandler();
this._bindSignals();
this._updateAnimationDuration();
this._updateAllAndSet();
this._updateProximityWatch();
},
destroy: function() {
this._signalsHandler.destroy();
this._proximityManager.removeWatch(this._proximityWatchId);
this._dtpPanel.set_style(this._initialPanelStyle);
if (this._dtpPanel._leftCorner) {
this._dtpPanel._leftCorner.actor.set_style(this._initialPanelCornerStyle);
this._dtpPanel._rightCorner.actor.set_style(this._initialPanelCornerStyle);
}
},
_bindSignals: function() {
this._signalsHandler.add(
[
St.ThemeContext.get_for_stage(global.stage),
'changed',
() => this._updateAllAndSet()
],
[
Main.overview,
[
'showing',
'hiding'
],
() => this._updateAlphaAndSet()
],
[
Me.settings,
[
'changed::trans-use-custom-bg',
'changed::trans-bg-color'
],
() => this._updateColorAndSet()
],
[
Me.settings,
[
'changed::trans-use-custom-opacity',
'changed::trans-panel-opacity',
'changed::trans-bg-color',
'changed::trans-dynamic-anim-target',
'changed::trans-use-dynamic-opacity'
],
() => this._updateAlphaAndSet()
],
[
Me.settings,
[
'changed::trans-use-custom-gradient',
'changed::trans-gradient-top-color',
'changed::trans-gradient-bottom-color',
'changed::trans-gradient-top-opacity',
'changed::trans-gradient-bottom-opacity'
],
() => this._updateGradientAndSet()
],
[
Me.settings,
[
'changed::trans-dynamic-behavior',
'changed::trans-use-dynamic-opacity',
'changed::trans-dynamic-distance'
],
() => this._updateProximityWatch()
],
[
Me.settings,
'changed::trans-dynamic-anim-time',
() => this._updateAnimationDuration()
]
);
},
_updateProximityWatch: function() {
this._proximityManager.removeWatch(this._proximityWatchId);
if (Me.settings.get_boolean('trans-use-dynamic-opacity')) {
let isVertical = Panel.checkIfVertical();
let threshold = Me.settings.get_int('trans-dynamic-distance');
this._proximityWatchId = this._proximityManager.createWatch(
this._dtpPanel.panelBox,
Proximity.Mode[Me.settings.get_string('trans-dynamic-behavior')],
isVertical ? threshold : 0,
isVertical ? 0 : threshold,
overlap => {
this._windowOverlap = overlap;
this._updateAlphaAndSet();
}
);
}
},
_updateAnimationDuration: function() {
this.animationDuration = (Me.settings.get_int('trans-dynamic-anim-time') * 0.001) + 's;';
},
_updateAllAndSet: function() {
let themeBackground = this._getThemeBackground(true);
this._updateColor(themeBackground);
this._updateAlpha(themeBackground);
this._updateComplementaryStyles();
this._updateGradient();
this._setBackground();
this._setGradient();
},
_updateColorAndSet: function() {
this._updateColor();
this._setBackground();
},
_updateAlphaAndSet: function() {
this._updateAlpha();
this._setBackground();
},
_updateGradientAndSet: function() {
this._updateGradient();
this._setGradient();
},
_updateComplementaryStyles: function() {
let panelThemeNode = this._dtpPanel.get_theme_node();
this._complementaryStyles = 'border-radius: ' + panelThemeNode.get_border_radius(0) + 'px;';
},
_updateColor: function(themeBackground) {
this.backgroundColorRgb = Me.settings.get_boolean('trans-use-custom-bg') ?
Me.settings.get_string('trans-bg-color') :
(themeBackground || this._getThemeBackground());
},
_updateAlpha: function(themeBackground) {
if (this._windowOverlap && !Main.overview.visibleTarget && Me.settings.get_boolean('trans-use-dynamic-opacity')) {
this.alpha = Me.settings.get_double('trans-dynamic-anim-target');
} else {
this.alpha = Me.settings.get_boolean('trans-use-custom-opacity') ?
Me.settings.get_double('trans-panel-opacity') :
(themeBackground || this._getThemeBackground()).alpha * 0.003921569; // 1 / 255 = 0.003921569
}
},
_updateGradient: function() {
this._gradientStyle = '';
if (Me.settings.get_boolean('trans-use-custom-gradient')) {
this._gradientStyle += 'background-gradient-direction: ' + (Panel.checkIfVertical() ? 'horizontal;' : 'vertical;') +
'background-gradient-start: ' + Utils.getrgbaColor(Me.settings.get_string('trans-gradient-top-color'),
Me.settings.get_double('trans-gradient-top-opacity')) +
'background-gradient-end: ' + Utils.getrgbaColor(Me.settings.get_string('trans-gradient-bottom-color'),
Me.settings.get_double('trans-gradient-bottom-opacity'));
}
},
_setBackground: function() {
this.currentBackgroundColor = Utils.getrgbaColor(this.backgroundColorRgb, this.alpha);
let transition = 'transition-duration:' + this.animationDuration;
let cornerStyle = '-panel-corner-background-color: ' + this.currentBackgroundColor + transition;
this._dtpPanel.bg.set_style('background-color: ' + this.currentBackgroundColor + transition + this._complementaryStyles);
if (this._dtpPanel._leftCorner) {
this._dtpPanel._leftCorner.actor.set_style(cornerStyle);
this._dtpPanel._rightCorner.actor.set_style(cornerStyle);
}
},
_setGradient: function() {
this._dtpPanel.set_style(
'background: none; ' +
'border-image: none; ' +
'background-image: none; ' +
this._gradientStyle +
'transition-duration:' + this.animationDuration
);
},
_getThemeBackground: function(reload) {
if (reload || !this._themeBackground) {
let fakePanel = new St.Bin({ name: 'panel' });
Main.uiGroup.add_child(fakePanel);
let fakeTheme = fakePanel.get_theme_node()
this._themeBackground = this._getBackgroundImageColor(fakeTheme) || fakeTheme.get_background_color();
Main.uiGroup.remove_child(fakePanel);
}
return this._themeBackground;
},
_getBackgroundImageColor: function(theme) {
let bg = null;
try {
let imageFile = theme.get_background_image() || theme.get_border_image().get_file();
if (imageFile) {
let imageBuf = GdkPixbuf.Pixbuf.new_from_file(imageFile.get_path());
let pixels = imageBuf.get_pixels();
bg = { red: pixels[0], green: pixels[1], blue: pixels[2], alpha: pixels[3] };
}
} catch (error) {}
return bg;
}
});
\ No newline at end of file
/*
* This file is part of the Dash-To-Panel extension for Gnome 3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Soup = imports.gi.Soup;
const FileUtils = imports.misc.fileUtils;
const Me = imports.misc.extensionUtils.getCurrentExtension();
const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']);
const _ = Gettext.gettext;
let apiUrl = '';
function init() {
Me.settings.connect('changed::force-check-update', () => {
if (Me.settings.get_boolean('force-check-update')) {
checkForUpdate(true);
Me.settings.set_boolean('force-check-update', false);
}
});
}
function checkForUpdate(fromSettings) {
if (!apiUrl) {
return notifyError(_('Unavailable when installed from extensions.gnome.org'));
}
}
function notifyError(err) {
Me.imports.utils.notify(_('Error: ') + err, 'dialog-error', null, true);
}
function notify(msg, action) {
Me.imports.utils.notify(msg, 'dialog-information', action, true);
}
/*
* This file is part of the Dash-To-Panel extension for Gnome 3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
* Credits:
* This file is based on code from the Dash to Dock extension by micheleg
* and code from the Taskbar extension by Zorin OS
* Some code was also adapted from the upstream Gnome Shell source code.
*/
const Clutter = imports.gi.Clutter;
const GdkPixbuf = imports.gi.GdkPixbuf
const Gi = imports._gi;
const Gio = imports.gi.Gio;
const GObject = imports.gi.GObject;
const Gtk = imports.gi.Gtk;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Mainloop = imports.mainloop;
const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
const Tweener = imports.ui.tweener;
const Util = imports.misc.util;
var TRANSLATION_DOMAIN = imports.misc.extensionUtils.getCurrentExtension().metadata['gettext-domain'];
var SCROLL_TIME = Util.SCROLL_TIME / (Util.SCROLL_TIME > 1 ? 1000 : 1);
var defineClass = function (classDef) {
let parentProto = classDef.Extends ? classDef.Extends.prototype : null;
if (imports.misc.config.PACKAGE_VERSION < '3.31.9') {
if (parentProto && (classDef.Extends.name || classDef.Extends.toString()).indexOf('DashToPanel.') < 0) {
classDef.callParent = function() {
let args = Array.prototype.slice.call(arguments);
let func = args.shift();
classDef.Extends.prototype[func].apply(this, args);
};
}
return new imports.lang.Class(classDef);
}
let isGObject = parentProto instanceof GObject.Object;
let needsSuper = parentProto && !isGObject;
let getParentArgs = function(args) {
let parentArgs = [];
(classDef.ParentConstrParams || parentArgs).forEach(p => {
if (p.constructor === Array) {
let param = args[p[0]];
parentArgs.push(p[1] ? param[p[1]] : param);
} else {
parentArgs.push(p);
}
});
return parentArgs;
};
let C = eval(
'(class C ' + (needsSuper ? 'extends Object' : '') + ' { ' +
' constructor(...args) { ' +
(needsSuper ? 'super(...getParentArgs(args));' : '') +
(needsSuper || !parentProto ? 'this._init(...args);' : '') +
' }' +
' callParent(...args) { ' +
' let func = args.shift(); ' +
' if (!(func === \'_init\' && needsSuper))' +
' super[func](...args); ' +
' }' +
'})'
);
if (parentProto) {
Object.setPrototypeOf(C.prototype, parentProto);
Object.setPrototypeOf(C, classDef.Extends);
}
Object.defineProperty(C, 'name', { value: classDef.Name });
Object.keys(classDef)
.filter(k => classDef.hasOwnProperty(k) && classDef[k] instanceof Function)
.forEach(k => C.prototype[k] = classDef[k]);
if (isGObject) {
C = GObject.registerClass({ Signals: classDef.Signals || {} }, C);
}
return C;
};
// simplify global signals and function injections handling
// abstract class
var BasicHandler = defineClass({
Name: 'DashToPanel.BasicHandler',
_init: function(){
this._storage = new Object();
},
add: function(/*unlimited 3-long array arguments*/){
// convert arguments object to array, concatenate with generic
let args = Array.concat('generic', Array.slice(arguments));
// call addWithLabel with ags as if they were passed arguments
this.addWithLabel.apply(this, args);
},
destroy: function() {
for( let label in this._storage )
this.removeWithLabel(label);
},
addWithLabel: function( label /* plus unlimited 3-long array arguments*/) {
if(this._storage[label] == undefined)
this._storage[label] = new Array();
// skip first element of the arguments
for( let i = 1; i < arguments.length; i++ ) {
let item = this._storage[label];
let handlers = this._create(arguments[i]);
for (let j = 0, l = handlers.length; j < l; ++j) {
item.push(handlers[j]);
}
}
},
removeWithLabel: function(label){
if(this._storage[label]) {
for( let i = 0; i < this._storage[label].length; i++ ) {
this._remove(this._storage[label][i]);
}
delete this._storage[label];
}
},
/* Virtual methods to be implemented by subclass */
// create single element to be stored in the storage structure
_create: function(item){
throw new Error('no implementation of _create in ' + this);
},
// correctly delete single element
_remove: function(item){
throw new Error('no implementation of _remove in ' + this);
}
});
// Manage global signals
var GlobalSignalsHandler = defineClass({
Name: 'DashToPanel.GlobalSignalsHandler',
Extends: BasicHandler,
_create: function(item) {
let handlers = [];
item[1] = [].concat(item[1]);
for (let i = 0, l = item[1].length; i < l; ++i) {
let object = item[0];
let event = item[1][i];
let callback = item[2]
let id = object.connect(event, callback);
handlers.push([object, id]);
}
return handlers;
},
_remove: function(item){
item[0].disconnect(item[1]);
}
});
/**
* Manage function injection: both instances and prototype can be overridden
* and restored
*/
var InjectionsHandler = defineClass({
Name: 'DashToPanel.InjectionsHandler',
Extends: BasicHandler,
_create: function(item) {
let object = item[0];
let name = item[1];
let injectedFunction = item[2];
let original = object[name];
object[name] = injectedFunction;
return [[object, name, injectedFunction, original]];
},
_remove: function(item) {
let object = item[0];
let name = item[1];
let original = item[3];
object[name] = original;
}
});
/**
* Manage timeouts: the added timeouts have their id reset on completion
*/
var TimeoutsHandler = defineClass({
Name: 'DashToPanel.TimeoutsHandler',
Extends: BasicHandler,
_create: function(item) {
let name = item[0];
let delay = item[1];
let timeoutHandler = item[2];
this._remove(item);
this[name] = Mainloop.timeout_add(delay, () => {
this[name] = 0;
timeoutHandler();
});
return [[name]];
},
remove: function(name) {
this._remove([name])
},
_remove: function(item) {
let name = item[0];
if (this[name]) {
Mainloop.source_remove(this[name]);
this[name] = 0;
}
},
getId: function(name) {
return this[name] ? this[name] : 0;
}
});
// This is wrapper to maintain compatibility with GNOME-Shell 3.30+ as well as
// previous versions.
var DisplayWrapper = {
getScreen: function() {
return global.screen || global.display;
},
getWorkspaceManager: function() {
return global.screen || global.workspace_manager;
},
getMonitorManager: function() {
return global.screen || Meta.MonitorManager.get();
}
};
var getCurrentWorkspace = function() {
return DisplayWrapper.getWorkspaceManager().get_active_workspace();
};
var getWorkspaceByIndex = function(index) {
return DisplayWrapper.getWorkspaceManager().get_workspace_by_index(index);
};
var getWorkspaceCount = function() {
return DisplayWrapper.getWorkspaceManager().n_workspaces;
};
var checkIfWindowHasTransient = function(window) {
let hasTransient;
window.foreach_transient(t => !(hasTransient = true));
return hasTransient;
};
var findIndex = function(array, predicate) {
if (Array.prototype.findIndex) {
return array.findIndex(predicate);
}
for (let i = 0, l = array.length; i < l; ++i) {
if (predicate(array[i])) {
return i;
}
}
return -1;
};
var mergeObjects = function(main, bck) {
for (var prop in bck) {
if (!main.hasOwnProperty(prop) && bck.hasOwnProperty(prop)) {
main[prop] = bck[prop];
}
}
return main;
};
var hookVfunc = function(proto, symbol, func) {
if (Gi.hook_up_vfunc_symbol) {
//gjs > 1.53.3
proto[Gi.hook_up_vfunc_symbol](symbol, func);
} else {
//On older gjs, this is how to hook vfunc. It is buggy and can't be used reliably to replace
//already hooked functions. Since it's our only use for it, disabled for now (and probably forever)
//Gi.hook_up_vfunc(proto, symbol, func);
}
};
var wrapActor = function(actor) {
if (actor) {
Object.defineProperty(actor, 'actor', {
value: actor instanceof Clutter.Actor ? actor : actor.actor
});
}
};
var setClip = function(actor, x, y, width, height) {
actor.set_clip(0, 0, width, height);
actor.set_position(x, y);
actor.set_size(width, height);
};
var addKeybinding = function(key, settings, handler, modes) {
if (!Main.wm._allowedKeybindings[key]) {
Main.wm.addKeybinding(
key,
settings,
Meta.KeyBindingFlags.NONE,
modes || (Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW),
handler
);
}
};
var removeKeybinding = function(key) {
if (Main.wm._allowedKeybindings[key]) {
Main.wm.removeKeybinding(key);
}
};
var getrgbaColor = function(color, alpha, offset) {
if (alpha <= 0) {
return 'transparent; ';
}
color = typeof color === 'string' ? Clutter.color_from_string(color)[1] : color;
let rgb = { red: color.red, green: color.green, blue: color.blue };
if (offset) {
['red', 'green', 'blue'].forEach(k => {
rgb[k] = Math.min(255, Math.max(0, rgb[k] + offset));
if (rgb[k] == color[k]) {
rgb[k] = Math.min(255, Math.max(0, rgb[k] - offset));
}
});
}
return 'rgba(' + rgb.red + ',' + rgb.green + ',' + rgb.blue + ',' + (Math.floor(alpha * 100) * 0.01) + '); ' ;
};
var getMouseScrollDirection = function(event) {
let direction;
switch (event.get_scroll_direction()) {
case Clutter.ScrollDirection.UP:
case Clutter.ScrollDirection.LEFT:
direction = 'up';
break;
case Clutter.ScrollDirection.DOWN:
case Clutter.ScrollDirection.RIGHT:
direction = 'down';
break;
}
return direction;
};
var activateSiblingWindow = function(windows, direction, startWindow) {
let windowIndex = windows.indexOf(global.display.focus_window);
let nextWindowIndex = windowIndex < 0 ?
startWindow ? windows.indexOf(startWindow) : 0 :
windowIndex + (direction == 'up' ? 1 : -1);
if (nextWindowIndex == windows.length) {
nextWindowIndex = 0;
} else if (nextWindowIndex < 0) {
nextWindowIndex = windows.length - 1;
}
if (windowIndex != nextWindowIndex) {
Main.activateWindow(windows[nextWindowIndex]);
}
};
var notify = function(text, iconName, action, isTransient) {
let source = new MessageTray.SystemNotificationSource();
let notification = new MessageTray.Notification(source, 'Dash to Panel', text);
if (iconName) {
source.createIcon = function() {
return new St.Icon({ icon_name: iconName });
};
}
if (action) {
if (!(action instanceof Array)) {
action = [action];
}
action.forEach(a => notification.addAction(a.text, a.func));
}
Main.messageTray.add(source);
notification.setTransient(isTransient);
source.notify(notification);
};
/*
* This is a copy of the same function in utils.js, but also adjust horizontal scrolling
* and perform few further cheks on the current value to avoid changing the values when
* it would be clamp to the current one in any case.
* Return the amount of shift applied
*/
var ensureActorVisibleInScrollView = function(scrollView, actor, fadeSize, onComplete) {
let vadjustment = scrollView.vscroll.adjustment;
let hadjustment = scrollView.hscroll.adjustment;
let [vvalue, vlower, vupper, vstepIncrement, vpageIncrement, vpageSize] = vadjustment.get_values();
let [hvalue, hlower, hupper, hstepIncrement, hpageIncrement, hpageSize] = hadjustment.get_values();
let [hvalue0, vvalue0] = [hvalue, vvalue];
let voffset = fadeSize;
let hoffset = fadeSize;
let box = actor.get_allocation_box();
let y1 = box.y1, y2 = box.y2, x1 = box.x1, x2 = box.x2;
let parent = actor.get_parent();
while (parent != scrollView) {
if (!parent)
throw new Error("actor not in scroll view");
let box = parent.get_allocation_box();
y1 += box.y1;
y2 += box.y1;
x1 += box.x1;
x2 += box.x1;
parent = parent.get_parent();
}
if (y1 < vvalue + voffset)
vvalue = Math.max(0, y1 - voffset);
else if (vvalue < vupper - vpageSize && y2 > vvalue + vpageSize - voffset)
vvalue = Math.min(vupper -vpageSize, y2 + voffset - vpageSize);
if (x1 < hvalue + hoffset)
hvalue = Math.max(0, x1 - hoffset);
else if (hvalue < hupper - hpageSize && x2 > hvalue + hpageSize - hoffset)
hvalue = Math.min(hupper - hpageSize, x2 + hoffset - hpageSize);
let tweenOpts = {
time: SCROLL_TIME,
onComplete: onComplete || (() => {}),
transition: 'easeOutQuad'
};
if (vvalue !== vvalue0) {
Tweener.addTween(vadjustment, mergeObjects(tweenOpts, { value: vvalue }));
}
if (hvalue !== hvalue0) {
Tweener.addTween(hadjustment, mergeObjects(tweenOpts, { value: hvalue }));
}
return [hvalue- hvalue0, vvalue - vvalue0];
}
/**
* ColorUtils is adapted from https://github.com/micheleg/dash-to-dock
*/
var ColorUtils = {
colorLuminance: function(r, g, b, dlum) {
// Darken or brighten color by a fraction dlum
// Each rgb value is modified by the same fraction.
// Return "#rrggbb" strin
let rgbString = '#';
rgbString += ColorUtils._decimalToHex(Math.round(Math.min(Math.max(r*(1+dlum), 0), 255)), 2);
rgbString += ColorUtils._decimalToHex(Math.round(Math.min(Math.max(g*(1+dlum), 0), 255)), 2);
rgbString += ColorUtils._decimalToHex(Math.round(Math.min(Math.max(b*(1+dlum), 0), 255)), 2);
return rgbString;
},
_decimalToHex: function(d, padding) {
// Convert decimal to an hexadecimal string adding the desired padding
let hex = d.toString(16);
while (hex.length < padding)
hex = '0'+ hex;
return hex;
},
HSVtoRGB: function(h, s, v) {
// Convert hsv ([0-1, 0-1, 0-1]) to rgb ([0-255, 0-255, 0-255]).
// Following algorithm in https://en.wikipedia.org/wiki/HSL_and_HSV
// here with h = [0,1] instead of [0, 360]
// Accept either (h,s,v) independently or {h:h, s:s, v:v} object.
// Return {r:r, g:g, b:b} object.
if (arguments.length === 1) {
s = h.s;
v = h.v;
h = h.h;
}
let r,g,b;
let c = v*s;
let h1 = h*6;
let x = c*(1 - Math.abs(h1 % 2 - 1));
let m = v - c;
if (h1 <=1)
r = c + m, g = x + m, b = m;
else if (h1 <=2)
r = x + m, g = c + m, b = m;
else if (h1 <=3)
r = m, g = c + m, b = x + m;
else if (h1 <=4)
r = m, g = x + m, b = c + m;
else if (h1 <=5)
r = x + m, g = m, b = c + m;
else
r = c + m, g = m, b = x + m;
return {
r: Math.round(r * 255),
g: Math.round(g * 255),
b: Math.round(b * 255)
};
},
RGBtoHSV: function(r, g, b) {
// Convert rgb ([0-255, 0-255, 0-255]) to hsv ([0-1, 0-1, 0-1]).
// Following algorithm in https://en.wikipedia.org/wiki/HSL_and_HSV
// here with h = [0,1] instead of [0, 360]
// Accept either (r,g,b) independently or {r:r, g:g, b:b} object.
// Return {h:h, s:s, v:v} object.
if (arguments.length === 1) {
r = r.r;
g = r.g;
b = r.b;
}
let h,s,v;
let M = Math.max(r, g, b);
let m = Math.min(r, g, b);
let c = M - m;
if (c == 0)
h = 0;
else if (M == r)
h = ((g-b)/c) % 6;
else if (M == g)
h = (b-r)/c + 2;
else
h = (r-g)/c + 4;
h = h/6;
v = M/255;
if (M !== 0)
s = c/M;
else
s = 0;
return {h: h, s: s, v: v};
}
};
/**
* DominantColorExtractor is adapted from https://github.com/micheleg/dash-to-dock
*/
let themeLoader = null;
let iconCacheMap = new Map();
const MAX_CACHED_ITEMS = 1000;
const BATCH_SIZE_TO_DELETE = 50;
const DOMINANT_COLOR_ICON_SIZE = 64;
var DominantColorExtractor = defineClass({
Name: 'DashToPanel.DominantColorExtractor',
_init: function(app){
this._app = app;
},
/**
* Try to get the pixel buffer for the current icon, if not fail gracefully
*/
_getIconPixBuf: function() {
let iconTexture = this._app.create_icon_texture(16);
if (themeLoader === null) {
let ifaceSettings = new Gio.Settings({ schema: "org.gnome.desktop.interface" });
themeLoader = new Gtk.IconTheme(),
themeLoader.set_custom_theme(ifaceSettings.get_string('icon-theme')); // Make sure the correct theme is loaded
}
// Unable to load the icon texture, use fallback
if (iconTexture instanceof St.Icon === false) {
return null;
}
iconTexture = iconTexture.get_gicon();
// Unable to load the icon texture, use fallback
if (iconTexture === null) {
return null;
}
if (iconTexture instanceof Gio.FileIcon) {
// Use GdkPixBuf to load the pixel buffer from the provided file path
return GdkPixbuf.Pixbuf.new_from_file(iconTexture.get_file().get_path());
}
// Get the pixel buffer from the icon theme
let icon_info = themeLoader.lookup_icon(iconTexture.get_names()[0], DOMINANT_COLOR_ICON_SIZE, 0);
if (icon_info !== null)
return icon_info.load_icon();
else
return null;
},
/**
* The backlight color choosing algorithm was mostly ported to javascript from the
* Unity7 C++ source of Canonicals:
* https://bazaar.launchpad.net/~unity-team/unity/trunk/view/head:/launcher/LauncherIcon.cpp
* so it more or less works the same way.
*/
_getColorPalette: function() {
if (iconCacheMap.get(this._app.get_id())) {
// We already know the answer
return iconCacheMap.get(this._app.get_id());
}
let pixBuf = this._getIconPixBuf();
if (pixBuf == null)
return null;
let pixels = pixBuf.get_pixels(),
offset = 0;
let total = 0,
rTotal = 0,
gTotal = 0,
bTotal = 0;
let resample_y = 1,
resample_x = 1;
// Resampling of large icons
// We resample icons larger than twice the desired size, as the resampling
// to a size s
// DOMINANT_COLOR_ICON_SIZE < s < 2*DOMINANT_COLOR_ICON_SIZE,
// most of the case exactly DOMINANT_COLOR_ICON_SIZE as the icon size is tipycally
// a multiple of it.
let width = pixBuf.get_width();
let height = pixBuf.get_height();
// Resample
if (height >= 2* DOMINANT_COLOR_ICON_SIZE)
resample_y = Math.floor(height/DOMINANT_COLOR_ICON_SIZE);
if (width >= 2* DOMINANT_COLOR_ICON_SIZE)
resample_x = Math.floor(width/DOMINANT_COLOR_ICON_SIZE);
if (resample_x !==1 || resample_y !== 1)
pixels = this._resamplePixels(pixels, resample_x, resample_y);
// computing the limit outside the for (where it would be repeated at each iteration)
// for performance reasons
let limit = pixels.length;
for (let offset = 0; offset < limit; offset+=4) {
let r = pixels[offset],
g = pixels[offset + 1],
b = pixels[offset + 2],
a = pixels[offset + 3];
let saturation = (Math.max(r,g, b) - Math.min(r,g, b));
let relevance = 0.1 * 255 * 255 + 0.9 * a * saturation;
rTotal += r * relevance;
gTotal += g * relevance;
bTotal += b * relevance;
total += relevance;
}
total = total * 255;
let r = rTotal / total,
g = gTotal / total,
b = bTotal / total;
let hsv = ColorUtils.RGBtoHSV(r * 255, g * 255, b * 255);
if (hsv.s > 0.15)
hsv.s = 0.65;
hsv.v = 0.90;
let rgb = ColorUtils.HSVtoRGB(hsv.h, hsv.s, hsv.v);
// Cache the result.
let backgroundColor = {
lighter: ColorUtils.colorLuminance(rgb.r, rgb.g, rgb.b, 0.2),
original: ColorUtils.colorLuminance(rgb.r, rgb.g, rgb.b, 0),
darker: ColorUtils.colorLuminance(rgb.r, rgb.g, rgb.b, -0.5)
};
if (iconCacheMap.size >= MAX_CACHED_ITEMS) {
//delete oldest cached values (which are in order of insertions)
let ctr=0;
for (let key of iconCacheMap.keys()) {
if (++ctr > BATCH_SIZE_TO_DELETE)
break;
iconCacheMap.delete(key);
}
}
iconCacheMap.set(this._app.get_id(), backgroundColor);
return backgroundColor;
},
/**
* Downsample large icons before scanning for the backlight color to
* improve performance.
*
* @param pixBuf
* @param pixels
* @param resampleX
* @param resampleY
*
* @return [];
*/
_resamplePixels: function (pixels, resampleX, resampleY) {
let resampledPixels = [];
// computing the limit outside the for (where it would be repeated at each iteration)
// for performance reasons
let limit = pixels.length / (resampleX * resampleY) / 4;
for (let i = 0; i < limit; i++) {
let pixel = i * resampleX * resampleY;
resampledPixels.push(pixels[pixel * 4]);
resampledPixels.push(pixels[pixel * 4 + 1]);
resampledPixels.push(pixels[pixel * 4 + 2]);
resampledPixels.push(pixels[pixel * 4 + 3]);
}
return resampledPixels;
}
});
/*
* This file is part of the Dash-To-Panel extension for Gnome 3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
const Clutter = imports.gi.Clutter;
const Config = imports.misc.config;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
const Main = imports.ui.main;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
const PopupMenu = imports.ui.popupMenu;
const Signals = imports.signals;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Tweener = imports.ui.tweener;
const WindowManager = imports.ui.windowManager;
const Workspace = imports.ui.workspace;
const Me = imports.misc.extensionUtils.getCurrentExtension();
const Panel = Me.imports.panel;
const Taskbar = Me.imports.taskbar;
const Utils = Me.imports.utils;
//timeout intervals
const ENSURE_VISIBLE_MS = 200;
//timeout names
const T1 = 'openMenuTimeout';
const T2 = 'closeMenuTimeout';
const T3 = 'peekTimeout';
const T4 = 'ensureVisibleTimeout';
const MAX_TRANSLATION = 40;
const HEADER_HEIGHT = 38;
const MAX_CLOSE_BUTTON_SIZE = 30;
const MIN_DIMENSION = 100;
const FOCUSED_COLOR_OFFSET = 24;
const HEADER_COLOR_OFFSET = -12;
const FADE_SIZE = 36;
const PEEK_INDEX_PROP = '_dtpPeekInitialIndex';
let headerHeight = 0;
let clipHeight = 0;
let alphaBg = 0;
let isLeftButtons = false;
let isTopHeader = true;
let isManualStyling = false;
let scaleFactor = 1;
let animationTime = 0;
let aspectRatio = {};
var PreviewMenu = Utils.defineClass({
Name: 'DashToPanel-PreviewMenu',
Extends: St.Widget,
Signals: { 'open-state-changed': {} },
_init: function(panel) {
this.callParent('_init', { layout_manager: new Clutter.BinLayout() });
let geom = panel.geom;
this.panel = panel;
this.currentAppIcon = null;
this._focusedPreview = null;
this._peekedWindow = null;
this.peekInitialWorkspaceIndex = -1;
this.opened = false;
this.isVertical = geom.position == St.Side.LEFT || geom.position == St.Side.RIGHT;
this._translationProp = 'translation_' + (this.isVertical ? 'x' : 'y');
this._translationDirection = (geom.position == St.Side.TOP || geom.position == St.Side.LEFT ? -1 : 1);
this._translationOffset = Math.min(Panel.size, MAX_TRANSLATION) * this._translationDirection;
this.menu = new St.Widget({
name: 'preview-menu',
layout_manager: new Clutter.BinLayout(),
reactive: true,
track_hover: true,
x_expand: true,
y_expand: true,
x_align: Clutter.ActorAlign[geom.position != St.Side.RIGHT ? 'START' : 'END'],
y_align: Clutter.ActorAlign[geom.position != St.Side.BOTTOM ? 'START' : 'END']
});
this._box = new St.BoxLayout({ vertical: this.isVertical });
this._scrollView = new St.ScrollView({
name: 'dashtopanelPreviewScrollview',
hscrollbar_policy: Gtk.PolicyType.NEVER,
vscrollbar_policy: Gtk.PolicyType.NEVER,
enable_mouse_scrolling: true,
y_expand: !this.isVertical
});
this._scrollView.add_actor(this._box);
this.menu.add_child(this._scrollView);
this.add_child(this.menu);
},
enable: function() {
this._timeoutsHandler = new Utils.TimeoutsHandler();
this._signalsHandler = new Utils.GlobalSignalsHandler();
Main.layoutManager.addChrome(this, { affectsInputRegion: false });
Main.layoutManager.trackChrome(this.menu, { affectsInputRegion: true });
this._resetHiddenState();
this._refreshGlobals();
this._updateClip();
this.menu.set_position(1, 1);
this._signalsHandler.add(
[
this.menu,
'notify::hover',
() => this._onHoverChanged()
],
[
this._scrollView,
'scroll-event',
this._onScrollEvent.bind(this)
],
[
this.panel.panelBox,
'style-changed',
() => this._updateClip()
],
[
Utils.DisplayWrapper.getScreen(),
'in-fullscreen-changed',
() => {
if (global.display.focus_window && global.display.focus_window.is_fullscreen()) {
this.close(true);
}
}
],
[
Me.settings,
[
'changed::panel-size',
'changed::window-preview-size',
'changed::window-preview-padding',
'changed::window-preview-show-title'
],
() => {
this._refreshGlobals();
this._updateClip();
}
]
);
},
disable: function() {
this._timeoutsHandler.destroy();
this._signalsHandler.destroy();
this.close(true);
Main.layoutManager.untrackChrome(this.menu);
Main.layoutManager.removeChrome(this);
},
requestOpen: function(appIcon) {
this._endOpenCloseTimeouts();
this._timeoutsHandler.add([T1, Me.settings.get_int('show-window-previews-timeout'), () => this.open(appIcon)]);
},
requestClose: function() {
this._endOpenCloseTimeouts();
this._addCloseTimeout();
},
open: function(appIcon) {
if (this.currentAppIcon != appIcon) {
this.currentAppIcon = appIcon;
if (!this.opened) {
this._refreshGlobals();
this.set_height(clipHeight);
this.menu.show();
setStyle(this.menu, 'background: ' + Utils.getrgbaColor(this.panel.dynamicTransparency.backgroundColorRgb, alphaBg));
}
this._mergeWindows(appIcon);
this._updatePosition();
this._animateOpenOrClose(true);
this._setReactive(true);
this._setOpenedState(true);
}
},
close: function(immediate) {
this._endOpenCloseTimeouts();
this._removeFocus();
this._endPeek();
if (immediate) {
this._resetHiddenState();
} else {
this._animateOpenOrClose(false, () => this._resetHiddenState());
}
this._setReactive(false);
this.currentAppIcon = null;
},
update: function(appIcon, windows) {
if (this.currentAppIcon == appIcon) {
if (windows && !windows.length) {
this.close();
} else {
this._addAndRemoveWindows(windows);
this._updatePosition();
}
}
},
updatePosition: function() {
this._updatePosition();
},
focusNext: function() {
let previews = this._box.get_children();
let currentIndex = this._focusedPreview ? previews.indexOf(this._focusedPreview) : -1;
let nextIndex = currentIndex + 1;
nextIndex = previews[nextIndex] ? nextIndex : 0;
if (previews[nextIndex]) {
this._removeFocus();
previews[nextIndex].setFocus(true);
this._focusedPreview = previews[nextIndex];
}
return nextIndex;
},
activateFocused: function() {
if (this.opened && this._focusedPreview) {
this._focusedPreview.activate();
}
},
requestPeek: function(window) {
this._timeoutsHandler.remove(T3);
if (Me.settings.get_boolean('peek-mode')) {
if (this.peekInitialWorkspaceIndex < 0) {
this._timeoutsHandler.add([T3, Me.settings.get_int('enter-peek-mode-timeout'), () => this._peek(window)]);
} else {
this._peek(window);
}
}
},
endPeekHere: function() {
this._endPeek(true);
},
ensureVisible: function(preview) {
let [ , upper, pageSize] = this._getScrollAdjustmentValues();
if (upper > pageSize) {
this._timeoutsHandler.add([
T4,
ENSURE_VISIBLE_MS,
() => Utils.ensureActorVisibleInScrollView(this._scrollView, preview, MIN_DIMENSION, () => this._updateScrollFade())
]);
}
},
getCurrentAppIcon: function() {
return this.currentAppIcon;
},
_setReactive: function(reactive) {
this._box.get_children().forEach(c => c.reactive = reactive);
this.menu.reactive = reactive;
},
_setOpenedState: function(opened) {
this.opened = opened;
this.emit('open-state-changed');
},
_resetHiddenState: function() {
this.menu.hide();
this.set_height(0);
this._setOpenedState(false);
this.menu.opacity = 0;
this.menu[this._translationProp] = this._translationOffset;
this._box.get_children().forEach(c => c.destroy());
},
_removeFocus: function() {
if (this._focusedPreview) {
this._focusedPreview.setFocus(false);
this._focusedPreview = null;
}
},
_mergeWindows: function(appIcon, windows) {
windows = windows || (appIcon.window ? [appIcon.window] : appIcon.getAppIconInterestingWindows());
windows.sort(Taskbar.sortWindowsCompareFunction);
let currentPreviews = this._box.get_children();
let l = Math.max(windows.length, currentPreviews.length);
for (let i = 0; i < l; ++i) {
if (currentPreviews[i] && windows[i] && windows[i] != currentPreviews[i].window) {
currentPreviews[i].assignWindow(windows[i], this.opened);
} else if (!currentPreviews[i]) {
this._addNewPreview(windows[i]);
} else if (!windows[i]) {
currentPreviews[i][!this.opened ? 'destroy' : 'animateOut']();
}
}
},
_addAndRemoveWindows: function(windows) {
let currentPreviews = this._box.get_children();
windows.sort(Taskbar.sortWindowsCompareFunction);
for (let i = 0, l = windows.length; i < l; ++i) {
let currentIndex = Utils.findIndex(currentPreviews, c => c.window == windows[i]);
if (currentIndex < 0) {
this._addNewPreview(windows[i]);
} else {
currentPreviews[currentIndex].cancelAnimateOut();
currentPreviews[currentIndex].assignWindow(windows[i]);
currentPreviews.splice(currentIndex, 1);
if (this._peekedWindow && this._peekedWindow == windows[i]) {
this.requestPeek(windows[i]);
}
}
}
currentPreviews.forEach(c => c.animateOut());
},
_addNewPreview: function(window) {
let preview = new Preview(this);
this._box.add_child(preview);
preview.adjustOnStage();
preview.assignWindow(window, this.opened);
},
_addCloseTimeout: function() {
this._timeoutsHandler.add([T2, Me.settings.get_int('leave-timeout'), () => this.close()]);
},
_onHoverChanged: function() {
this._endOpenCloseTimeouts();
if (this.currentAppIcon && !this.menu.hover) {
this._addCloseTimeout();
this._endPeek();
}
},
_onScrollEvent: function(actor, event) {
if (!event.is_pointer_emulated()) {
let vOrh = this.isVertical ? 'v' : 'h';
let adjustment = this._scrollView['get_' + vOrh + 'scroll_bar']().get_adjustment();
let increment = adjustment.step_increment;
let delta = increment;
switch (event.get_scroll_direction()) {
case Clutter.ScrollDirection.UP:
delta = -increment;
break;
case Clutter.ScrollDirection.SMOOTH:
let [dx, dy] = event.get_scroll_delta();
delta = dy * increment;
delta += dx * increment;
break;
}
adjustment.set_value(adjustment.get_value() + delta);
this._updateScrollFade();
}
return Clutter.EVENT_STOP;
},
_endOpenCloseTimeouts: function() {
this._timeoutsHandler.remove(T1);
this._timeoutsHandler.remove(T2);
this._timeoutsHandler.remove(T4);
},
_refreshGlobals: function() {
isLeftButtons = Meta.prefs_get_button_layout().left_buttons.indexOf(Meta.ButtonFunction.CLOSE) >= 0;
isTopHeader = Me.settings.get_string('window-preview-title-position') == 'TOP';
isManualStyling = Me.settings.get_boolean('window-preview-manual-styling');
scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
headerHeight = Me.settings.get_boolean('window-preview-show-title') ? HEADER_HEIGHT * scaleFactor : 0;
animationTime = Me.settings.get_int('window-preview-animation-time') * .001;
aspectRatio.x = {
size: Me.settings.get_int('window-preview-aspect-ratio-x'),
fixed: Me.settings.get_boolean('window-preview-fixed-x')
};
aspectRatio.y = {
size: Me.settings.get_int('window-preview-aspect-ratio-y'),
fixed: Me.settings.get_boolean('window-preview-fixed-y')
};
if (this.panel.dynamicTransparency) {
alphaBg = Me.settings.get_boolean('preview-use-custom-opacity') ?
Me.settings.get_int('preview-custom-opacity') * .01 :
this.panel.dynamicTransparency.alpha;
}
},
_updateClip: function() {
let x, y, w;
let geom = this.panel.getGeometry();
let panelBoxTheme = this.panel.panelBox.get_theme_node();
let previewSize = (Me.settings.get_int('window-preview-size') +
Me.settings.get_int('window-preview-padding') * 2) * scaleFactor;
if (this.isVertical) {
w = previewSize;
clipHeight = this.panel.monitor.height;
y = this.panel.monitor.y;
} else {
w = this.panel.monitor.width;
clipHeight = (previewSize + headerHeight);
x = this.panel.monitor.x;
}
if (geom.position == St.Side.LEFT) {
x = this.panel.monitor.x + Panel.size + panelBoxTheme.get_padding(St.Side.LEFT);
} else if (geom.position == St.Side.RIGHT) {
x = this.panel.monitor.x + this.panel.monitor.width - (Panel.size + previewSize) - panelBoxTheme.get_padding(St.Side.RIGHT);
} else if (geom.position == St.Side.TOP) {
y = this.panel.monitor.y + Panel.size + panelBoxTheme.get_padding(St.Side.TOP);
} else { //St.Side.BOTTOM
y = this.panel.monitor.y + this.panel.monitor.height - (Panel.size + panelBoxTheme.get_padding(St.Side.BOTTOM) + previewSize + headerHeight);
}
Utils.setClip(this, x, y, w, clipHeight);
},
_updatePosition: function() {
let sourceNode = this.currentAppIcon.actor.get_theme_node();
let sourceContentBox = sourceNode.get_content_box(this.currentAppIcon.actor.get_allocation_box());
let sourceAllocation = Shell.util_get_transformed_allocation(this.currentAppIcon.actor);
let [previewsWidth, previewsHeight] = this._getPreviewsSize();
let appIconMargin = Me.settings.get_int('appicon-margin') / scaleFactor;
let x = 0, y = 0;
previewsWidth = Math.min(previewsWidth, this.panel.monitor.width);
previewsHeight = Math.min(previewsHeight, this.panel.monitor.height);
this._updateScrollFade(previewsWidth < this.panel.monitor.width && previewsHeight < this.panel.monitor.height);
if (this.isVertical) {
y = sourceAllocation.y1 + appIconMargin - this.panel.monitor.y + (sourceContentBox.y2 - sourceContentBox.y1 - previewsHeight) * .5;
y = Math.max(y, 0);
y = Math.min(y, this.panel.monitor.height - previewsHeight);
} else {
x = sourceAllocation.x1 + appIconMargin - this.panel.monitor.x + (sourceContentBox.x2 - sourceContentBox.x1 - previewsWidth) * .5;
x = Math.max(x, 0);
x = Math.min(x, this.panel.monitor.width - previewsWidth);
}
if (!this.opened) {
this.menu.set_position(x, y);
this.menu.set_size(previewsWidth, previewsHeight);
} else {
Tweener.addTween(this.menu, getTweenOpts({ x: x, y: y, width: previewsWidth, height: previewsHeight }));
}
},
_updateScrollFade: function(remove) {
let [value, upper, pageSize] = this._getScrollAdjustmentValues();
let needsFade = Math.round(upper) > Math.round(pageSize);
let fadeWidgets = this.menu.get_children().filter(c => c != this._scrollView);
if (!remove && needsFade) {
if (!fadeWidgets.length) {
fadeWidgets.push(this._getFadeWidget());
fadeWidgets.push(this._getFadeWidget(true));
this.menu.add_child(fadeWidgets[0]);
this.menu.add_child(fadeWidgets[1]);
}
fadeWidgets[0].visible = value > 0;
fadeWidgets[1].visible = value + pageSize < upper;
} else if (remove || (!needsFade && fadeWidgets.length)) {
fadeWidgets.forEach(fw => fw.destroy());
}
},
_getScrollAdjustmentValues: function() {
let [value , , upper, , , pageSize] = this._scrollView[(this.isVertical ? 'v' : 'h') + 'scroll'].adjustment.get_values();
return [value, upper, pageSize];
},
_getFadeWidget: function(end) {
let x = 0, y = 0;
let startBg = Utils.getrgbaColor(this.panel.dynamicTransparency.backgroundColorRgb, Math.min(alphaBg + .1, 1));
let endBg = Utils.getrgbaColor(this.panel.dynamicTransparency.backgroundColorRgb, 0)
let fadeStyle = 'background-gradient-start:' + startBg +
'background-gradient-end:' + endBg +
'background-gradient-direction:' + Panel.getOrientation();
if (this.isVertical) {
y = end ? this.panel.monitor.height - FADE_SIZE : 0;
} else {
x = end ? this.panel.monitor.width - FADE_SIZE : 0;
}
let fadeWidget = new St.Widget({
reactive: false,
pivot_point: new Clutter.Point({ x: .5, y: .5 }),
rotation_angle_z: end ? 180 : 0,
style: fadeStyle,
x: x, y: y,
width: this.isVertical ? this.width : FADE_SIZE,
height: this.isVertical ? FADE_SIZE : this.height
});
return fadeWidget;
},
_getPreviewsSize: function() {
let previewsWidth = 0;
let previewsHeight = 0;
this._box.get_children().forEach(c => {
if (!c.animatingOut) {
let [width, height] = c.getSize();
if (this.isVertical) {
previewsWidth = Math.max(width, previewsWidth);
previewsHeight += height;
} else {
previewsWidth += width;
previewsHeight = Math.max(height, previewsHeight);
}
}
});
return [previewsWidth, previewsHeight];
},
_animateOpenOrClose: function(show, onComplete) {
let isTranslationAnimation = this.menu[this._translationProp] != 0;
let tweenOpts = {
opacity: show ? 255 : 0,
transition: show ? 'easeInOutQuad' : 'easeInCubic',
onComplete: () => {
if (isTranslationAnimation) {
Main.layoutManager._queueUpdateRegions();
}
(onComplete || (() => {}))();
}
};
tweenOpts[this._translationProp] = show ? this._translationDirection : this._translationOffset;
Tweener.addTween(this.menu, getTweenOpts(tweenOpts));
},
_peek: function(window) {
let currentWorkspace = Utils.getCurrentWorkspace();
let windowWorkspace = window.get_workspace();
let focusWindow = () => this._focusMetaWindow(Me.settings.get_int('peek-mode-opacity'), window);
this._restorePeekedWindowStack();
this._peekedWindow = window;
if (currentWorkspace != windowWorkspace) {
this._switchToWorkspaceImmediate(windowWorkspace.index());
this._timeoutsHandler.add([T3, 100, focusWindow]);
} else {
focusWindow();
}
if (this.peekInitialWorkspaceIndex < 0) {
this.peekInitialWorkspaceIndex = currentWorkspace.index();
}
},
_endPeek: function(stayHere) {
this._timeoutsHandler.remove(T3);
if (this._peekedWindow) {
this._restorePeekedWindowStack();
this._focusMetaWindow(255);
this._peekedWindow = null;
if (!stayHere) {
this._switchToWorkspaceImmediate(this.peekInitialWorkspaceIndex);
}
this.peekInitialWorkspaceIndex = -1;
}
},
_switchToWorkspaceImmediate: function(workspaceIndex) {
let workspace = Utils.getWorkspaceByIndex(workspaceIndex);
if (!workspace || (!workspace.list_windows().length &&
workspaceIndex < Utils.getWorkspaceCount() -1)) {
workspace = Utils.getCurrentWorkspace();
}
Main.wm._blockAnimations = true;
workspace.activate(global.display.get_current_time_roundtrip());
Main.wm._blockAnimations = false;
},
_focusMetaWindow: function(dimOpacity, window) {
if (Main.overview.visibleTarget) {
return;
}
global.get_window_actors().forEach(wa => {
let mw = wa.meta_window;
let isFocused = mw == window;
if (mw) {
if (isFocused) {
mw[PEEK_INDEX_PROP] = wa.get_parent().get_children().indexOf(wa);
wa.get_parent().set_child_above_sibling(wa, null);
}
if (isFocused && mw.minimized) {
wa.show();
}
Tweener.addTween(wa, getTweenOpts({ opacity: isFocused ? 255 : dimOpacity }));
}
});
},
_restorePeekedWindowStack: function() {
let windowActor = this._peekedWindow ? this._peekedWindow.get_compositor_private() : null;
if (windowActor) {
if (this._peekedWindow.hasOwnProperty(PEEK_INDEX_PROP)) {
windowActor.get_parent().set_child_at_index(windowActor, this._peekedWindow[PEEK_INDEX_PROP]);
delete this._peekedWindow[PEEK_INDEX_PROP];
}
if(this._peekedWindow.minimized) {
windowActor.hide();
}
}
},
});
var Preview = Utils.defineClass({
Name: 'DashToPanel-Preview',
Extends: St.Widget,
_init: function(previewMenu) {
this.callParent('_init', {
style_class: 'preview-container',
reactive: true,
track_hover: true,
layout_manager: new Clutter.BinLayout()
});
this.window = null;
this._waitWindowId = 0;
this._needsCloseButton = true;
this.cloneWidth = this.cloneHeight = 0;
this._previewMenu = previewMenu;
this._padding = Me.settings.get_int('window-preview-padding') * scaleFactor;
this._previewDimensions = this._getPreviewDimensions();
this.animatingOut = false;
let box = new St.Widget({ layout_manager: new Clutter.BoxLayout({ vertical: true }), y_expand: true });
let [previewBinWidth, previewBinHeight] = this._getBinSize();
let closeButton = new St.Button({ style_class: 'window-close', accessible_name: 'Close window' });
if (Config.PACKAGE_VERSION >= '3.31.9') {
closeButton.add_actor(new St.Icon({ icon_name: 'window-close-symbolic' }));
}
this._closeButtonBin = new St.Widget({
style_class: 'preview-close-btn-container',
layout_manager: new Clutter.BinLayout(),
opacity: 0,
x_expand: true, y_expand: true,
x_align: Clutter.ActorAlign[isLeftButtons ? 'START' : 'END'],
y_align: Clutter.ActorAlign[isTopHeader ? 'START' : 'END']
});
this._closeButtonBin.add_child(closeButton);
this._previewBin = new St.Widget({
layout_manager: new Clutter.BinLayout(),
x_expand: true, y_expand: true,
style: 'padding: ' + this._padding / scaleFactor + 'px;'
});
this._previewBin.set_size(previewBinWidth, previewBinHeight);
box.add_child(this._previewBin);
if (headerHeight) {
let headerBox = new St.Widget({
style_class: 'preview-header-box',
layout_manager: new Clutter.BoxLayout(),
x_expand: true,
y_align: Clutter.ActorAlign[isTopHeader ? 'START' : 'END']
});
setStyle(headerBox, this._getBackgroundColor(HEADER_COLOR_OFFSET, 1));
this._workspaceIndicator = new St.Label({ y_align: Clutter.ActorAlign.CENTER });
this._windowTitle = new St.Label({ y_align: Clutter.ActorAlign.CENTER, x_expand: true });
this._iconBin = new St.Widget({ layout_manager: new Clutter.BinLayout() });
this._iconBin.set_size(headerHeight, headerHeight);
headerBox.add_child(this._iconBin);
headerBox.insert_child_at_index(this._workspaceIndicator, isLeftButtons ? 0 : 1);
headerBox.insert_child_at_index(this._windowTitle, isLeftButtons ? 1 : 2);
box.insert_child_at_index(headerBox, isTopHeader ? 0 : 1);
}
this.add_child(box);
this.add_child(this._closeButtonBin);
closeButton.connect('clicked', () => this._onCloseBtnClick());
this.connect('notify::hover', () => this._onHoverChanged());
this.connect('button-release-event', (actor, e) => this._onButtonReleaseEvent(e));
this.connect('destroy', () => this._onDestroy());
},
adjustOnStage: function() {
let closeButton = this._closeButtonBin.get_first_child();
let closeButtonHeight = closeButton.height;
let maxCloseButtonSize = MAX_CLOSE_BUTTON_SIZE * scaleFactor;
let closeButtonBorderRadius = '';
if (closeButtonHeight > maxCloseButtonSize) {
closeButtonHeight = maxCloseButtonSize;
closeButton.set_size(closeButtonHeight, closeButtonHeight);
}
if (!headerHeight) {
closeButtonBorderRadius = 'border-radius: ';
if (isTopHeader) {
closeButtonBorderRadius += (isLeftButtons ? '0 0 4px 0;' : '0 0 0 4px;');
} else {
closeButtonBorderRadius += (isLeftButtons ? '0 4px 0 0;' : '4px 0 0 0;');
}
}
setStyle(
this._closeButtonBin,
'padding: ' + (headerHeight ? Math.round((headerHeight - closeButtonHeight) * .5 / scaleFactor) : 4) + 'px;' +
this._getBackgroundColor(HEADER_COLOR_OFFSET, headerHeight ? 1 : .6) +
closeButtonBorderRadius
);
},
assignWindow: function(window, animateSize) {
if (this.window != window) {
let _assignWindowClone = () => {
if (window.get_compositor_private()) {
let cloneBin = this._getWindowCloneBin(window);
this._resizeClone(cloneBin, window);
this._addClone(cloneBin, animateSize);
this._previewMenu.updatePosition();
} else if (!this._waitWindowId) {
this._waitWindowId = Mainloop.idle_add(() => {
this._waitWindowId = 0;
_assignWindowClone();
});
}
};
_assignWindowClone();
}
this._removeWindowSignals();
this.window = window;
this._needsCloseButton = window.can_close() && !Utils.checkIfWindowHasTransient(window);
this._updateHeader();
},
animateOut: function() {
if (!this.animatingOut) {
let tweenOpts = getTweenOpts({ opacity: 0, width: 0, height: 0, onComplete: () => this.destroy() });
this.animatingOut = true;
Tweener.removeTweens(this);
Tweener.addTween(this, tweenOpts);
}
},
cancelAnimateOut: function() {
if (this.animatingOut) {
this.animatingOut = false;
Tweener.removeTweens(this);
Tweener.addTween(this, getTweenOpts({ opacity: 255 }));
}
},
getSize: function() {
let [binWidth, binHeight] = this._getBinSize();
binWidth = Math.max(binWidth, this.cloneWidth + this._padding * 2);
binHeight = Math.max(binHeight, this.cloneHeight + this._padding * 2) + headerHeight;
return [binWidth, binHeight];
},
setFocus: function(focused) {
this._hideOrShowCloseButton(!focused);
setStyle(this, this._getBackgroundColor(FOCUSED_COLOR_OFFSET, focused ? '-' : 0));
if (focused) {
this._previewMenu.ensureVisible(this);
this._previewMenu.requestPeek(this.window);
}
},
activate: function() {
this._previewMenu.endPeekHere();
this._previewMenu.close();
Main.activateWindow(this.window);
},
_onDestroy: function() {
if (this._waitWindowId) {
GLib.source_remove(this._waitWindowId);
this._waitWindowId = 0;
}
this._removeWindowSignals();
},
_onHoverChanged: function() {
this.setFocus(this.hover);
},
_onCloseBtnClick: function() {
this.window.delete(global.get_current_time());
this._hideOrShowCloseButton(true);
this.reactive = false;
if (!Me.settings.get_boolean('group-apps')) {
this._previewMenu.close();
}
},
_onButtonReleaseEvent: function(e) {
switch (e.get_button()) {
case 1: // Left click
this.activate();
break;
case 2: // Middle click
if (Me.settings.get_boolean('preview-middle-click-close')) {
this._onCloseBtnClick();
}
break;
case 3: // Right click
this._showContextMenu(e);
break;
}
return Clutter.EVENT_STOP;
},
_showContextMenu: function(e) {
let coords = e.get_coords();
let currentWorkspace = this._previewMenu.peekInitialWorkspaceIndex < 0 ?
Utils.getCurrentWorkspace() :
Utils.getWorkspaceByIndex(this._previewMenu.peekInitialWorkspaceIndex);
Main.wm._showWindowMenu(null, this.window, Meta.WindowMenuType.WM, {
x: coords[0],
y: coords[1],
width: 0,
height: 0
});
let ctxMenuData = Main.wm._windowMenuManager._manager._menus[0];
ctxMenuData.menu.connect('open-state-changed', () => this._previewMenu.menu.sync_hover());
if (this.window.get_workspace() != currentWorkspace) {
let menuItem = new PopupMenu.PopupMenuItem(_('Move to current Workspace') + ' [' + (currentWorkspace.index() + 1) + ']');
let menuItems = ctxMenuData.menu.box.get_children();
let insertIndex = Utils.findIndex(menuItems, c => c._delegate instanceof PopupMenu.PopupSeparatorMenuItem);
insertIndex = insertIndex >= 0 ? insertIndex : menuItems.length - 1;
ctxMenuData.menu.addMenuItem(menuItem, insertIndex);
menuItem.connect('activate', () => this.window.change_workspace(currentWorkspace));
}
},
_removeWindowSignals: function() {
if (this._titleWindowChangeId) {
this.window.disconnect(this._titleWindowChangeId);
this._titleWindowChangeId = 0;
}
},
_updateHeader: function() {
if (headerHeight) {
let iconTextureSize = headerHeight / scaleFactor * .6;
let icon = this._previewMenu.getCurrentAppIcon().app.create_icon_texture(iconTextureSize);
let workspaceIndex = '';
let workspaceStyle = null;
let commonTitleStyles = 'color: ' + Me.settings.get_string('window-preview-title-font-color') + ';' +
'font-size: ' + Me.settings.get_int('window-preview-title-font-size') + 'px;' +
'font-weight: ' + Me.settings.get_string('window-preview-title-font-weight') + ';';
this._iconBin.destroy_all_children();
this._iconBin.add_child(icon);
if (!Me.settings.get_boolean('isolate-workspaces')) {
workspaceIndex = (this.window.get_workspace().index() + 1).toString();
workspaceStyle = 'margin: 0 4px 0 ' + (isLeftButtons ? Math.round((headerHeight - icon.width) * .5) + 'px' : '0') + '; padding: 0 4px;' +
'border: 2px solid ' + this._getRgbaColor(FOCUSED_COLOR_OFFSET, .8) + 'border-radius: 2px;' + commonTitleStyles;
}
this._workspaceIndicator.text = workspaceIndex;
setStyle(this._workspaceIndicator, workspaceStyle);
this._titleWindowChangeId = this.window.connect('notify::title', () => this._updateWindowTitle());
setStyle(this._windowTitle, 'max-width: 0px; padding-right: 4px;' + commonTitleStyles);
this._updateWindowTitle();
}
},
_updateWindowTitle: function() {
this._windowTitle.text = this.window.title;
},
_hideOrShowCloseButton: function(hide) {
if (this._needsCloseButton) {
Tweener.addTween(this._closeButtonBin, getTweenOpts({ opacity: hide ? 0 : 255 }));
}
},
_getBackgroundColor: function(offset, alpha) {
return 'background-color: ' + this._getRgbaColor(offset, alpha) +
'transition-duration:' + this._previewMenu.panel.dynamicTransparency.animationDuration;
},
_getRgbaColor: function(offset, alpha) {
alpha = Math.abs(alpha);
if (isNaN(alpha)) {
alpha = alphaBg;
}
return Utils.getrgbaColor(this._previewMenu.panel.dynamicTransparency.backgroundColorRgb, alpha, offset);
},
_addClone: function(newCloneBin, animateSize) {
let currentClones = this._previewBin.get_children();
let newCloneOpts = getTweenOpts({ opacity: 255 });
this._previewBin.add_child(newCloneBin);
if (currentClones.length) {
let currentCloneBin = currentClones.pop();
let currentCloneOpts = getTweenOpts({ opacity: 0, onComplete: () => currentCloneBin.destroy() });
if (newCloneBin.width > currentCloneBin.width) {
newCloneOpts.width = newCloneBin.width;
newCloneBin.width = currentCloneBin.width;
} else {
currentCloneOpts.width = newCloneBin.width;
}
if (newCloneBin.height > currentCloneBin.height) {
newCloneOpts.height = newCloneBin.height;
newCloneBin.height = currentCloneBin.height;
} else {
currentCloneOpts.height = newCloneBin.height;
}
currentClones.forEach(c => c.destroy());
Tweener.addTween(currentCloneBin, currentCloneOpts);
} else if (animateSize) {
newCloneBin.width = 0;
newCloneBin.height = 0;
newCloneOpts.width = this.cloneWidth;
newCloneOpts.height = this.cloneHeight;
}
Tweener.addTween(newCloneBin, newCloneOpts);
},
_getWindowCloneBin: function(window) {
let frameRect = window.get_frame_rect();
let bufferRect = window.get_buffer_rect();
let clone = new Clutter.Clone({ source: window.get_compositor_private() });
let cloneBin = new St.Widget({
opacity: 0,
layout_manager: frameRect.width != bufferRect.width ||
frameRect.height != bufferRect.height ?
new WindowCloneLayout(frameRect, bufferRect) :
new Clutter.BinLayout()
});
cloneBin.add_child(clone);
return cloneBin;
},
_getBinSize: function() {
let [fixedWidth, fixedHeight] = this._previewDimensions;
return [
aspectRatio.x.fixed ? fixedWidth + this._padding * 2 : -1,
aspectRatio.y.fixed ? fixedHeight + this._padding * 2 : -1
];
},
_resizeClone: function(cloneBin, window) {
let frameRect = cloneBin.layout_manager.frameRect || window.get_frame_rect();
let [fixedWidth, fixedHeight] = this._previewDimensions;
let ratio = Math.min(fixedWidth / frameRect.width, fixedHeight / frameRect.height, 1);
let cloneWidth = frameRect.width * ratio;
let cloneHeight = frameRect.height * ratio;
let clonePaddingTB = cloneHeight < MIN_DIMENSION ? MIN_DIMENSION - cloneHeight : 0;
let clonePaddingLR = cloneWidth < MIN_DIMENSION ? MIN_DIMENSION - cloneWidth : 0;
let clonePaddingTop = clonePaddingTB * .5;
let clonePaddingLeft = clonePaddingLR * .5;
this.cloneWidth = cloneWidth + clonePaddingLR * scaleFactor;
this.cloneHeight = cloneHeight + clonePaddingTB * scaleFactor;
cloneBin.set_style('padding: ' + clonePaddingTop + 'px ' + clonePaddingLeft + 'px;');
cloneBin.layout_manager.ratio = ratio;
cloneBin.layout_manager.padding = [clonePaddingLeft * scaleFactor, clonePaddingTop * scaleFactor];
cloneBin.get_first_child().set_size(cloneWidth, cloneHeight);
},
_getPreviewDimensions: function() {
let size = Me.settings.get_int('window-preview-size') * scaleFactor;
let w, h;
if (this._previewMenu.isVertical) {
w = size;
h = w * aspectRatio.y.size / aspectRatio.x.size;
} else {
h = size;
w = h * aspectRatio.x.size / aspectRatio.y.size;
}
return [w, h];
}
});
var WindowCloneLayout = Utils.defineClass({
Name: 'DashToPanel-WindowCloneLayout',
Extends: Clutter.BinLayout,
_init: function(frameRect, bufferRect) {
this.callParent('_init');
//the buffer_rect contains the transparent padding that must be removed
this.frameRect = frameRect;
this.bufferRect = bufferRect;
},
vfunc_allocate: function(actor, box, flags) {
let [width, height] = box.get_size();
box.set_origin(
(this.bufferRect.x - this.frameRect.x) * this.ratio + this.padding[0],
(this.bufferRect.y - this.frameRect.y) * this.ratio + this.padding[1]
);
box.set_size(
width + (this.bufferRect.width - this.frameRect.width) * this.ratio,
height + (this.bufferRect.height - this.frameRect.height) * this.ratio
);
actor.get_first_child().allocate(box, flags);
}
});
function setStyle(actor, style) {
if (!isManualStyling) {
actor.set_style(style);
}
}
function getTweenOpts(opts) {
let defaults = {
time: animationTime,
transition: 'easeInOutQuad'
};
return Utils.mergeObjects(opts || {}, defaults);
}
\ No newline at end of file
/usr/lib/systemd/system/remove-classic.service
\ No newline at end of file
[Unit]
Description=Disable Gnome Classic
[Service]
ExecStart=/usr/local/bin/remove-classic.sh
[Install]
WantedBy=multi-user.target
#!/bin/bash
file=gnome-classic.desktop
if [ -f /usr/share/xsessions/$file ] ; then
mv /usr/share/xsessions/$file /usr/share/xsessions/gnome-classic~
fi
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="56.444447mm"
height="56.44445mm"
viewBox="0 0 200 200.00002"
id="svg2"
version="1.1"
inkscape:version="0.92.1 r"
sodipodi:docname="green.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.4142136"
inkscape:cx="30.692892"
inkscape:cy="126.5323"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:showpageshadow="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="1366"
inkscape:window-height="742"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:pagecheckerboard="true" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(222.41168,-236.90016)">
<g
id="g5967"
style="fill:#35bf5c;fill-opacity:1">
<g
id="g4446"
transform="matrix(1.2196132,0,0,1.0000088,-467.56616,-225.96506)"
style="fill:#35bf5c;fill-opacity:1">
<rect
style="opacity:1;fill:#35bf5c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:7.07399988;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:21.222, 21.22200000000000131;stroke-dashoffset:0;stroke-opacity:1"
id="rect4149-7"
width="47.994675"
height="199.99825"
x="317.00177"
y="462.86115" />
<rect
style="opacity:1;fill:#35bf5c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:7.07399988;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:21.222, 21.22200000000000131;stroke-dashoffset:0;stroke-opacity:1"
id="rect4149-0-6"
width="47.994675"
height="129.26767"
x="259.00415"
y="533.59174" />
</g>
<path
inkscape:connector-curvature="0"
id="path5961"
d="m -222.41168,236.90016 h 129.26633 v 58.53494 h -70.93002 v 141.46508 h -58.33631 z"
style="fill:#35bf5c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.93749994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
</g>
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="56.444447mm"
height="56.44445mm"
viewBox="0 0 200 200.00002"
id="svg2"
version="1.1"
inkscape:version="0.92.1 r"
sodipodi:docname="green.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.4142136"
inkscape:cx="30.692892"
inkscape:cy="126.5323"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:showpageshadow="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="1366"
inkscape:window-height="742"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:pagecheckerboard="true" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(222.41168,-236.90016)">
<g
id="g5967"
style="fill:#35bf5c;fill-opacity:1">
<g
id="g4446"
transform="matrix(1.2196132,0,0,1.0000088,-467.56616,-225.96506)"
style="fill:#35bf5c;fill-opacity:1">
<rect
style="opacity:1;fill:#35bf5c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:7.07399988;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:21.222, 21.22200000000000131;stroke-dashoffset:0;stroke-opacity:1"
id="rect4149-7"
width="47.994675"
height="199.99825"
x="317.00177"
y="462.86115" />
<rect
style="opacity:1;fill:#35bf5c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:7.07399988;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:21.222, 21.22200000000000131;stroke-dashoffset:0;stroke-opacity:1"
id="rect4149-0-6"
width="47.994675"
height="129.26767"
x="259.00415"
y="533.59174" />
</g>
<path
inkscape:connector-curvature="0"
id="path5961"
d="m -222.41168,236.90016 h 129.26633 v 58.53494 h -70.93002 v 141.46508 h -58.33631 z"
style="fill:#35bf5c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.93749994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
</g>
</svg>
QT_QPA_PLATFORMTHEME="qt5ct"
[General]
theme=Matchama
[Qt]
style=GTK+