2011-09-28 13:16:26 +00:00
|
|
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
2023-07-10 09:53:00 +00:00
|
|
|
|
|
|
|
import Clutter from 'gi://Clutter';
|
|
|
|
import GLib from 'gi://GLib';
|
|
|
|
import GObject from 'gi://GObject';
|
|
|
|
import Graphene from 'gi://Graphene';
|
|
|
|
import Meta from 'gi://Meta';
|
|
|
|
import Shell from 'gi://Shell';
|
|
|
|
import St from 'gi://St';
|
|
|
|
|
|
|
|
import * as AppDisplay from './appDisplay.js';
|
|
|
|
import * as AppFavorites from './appFavorites.js';
|
|
|
|
import * as DND from './dnd.js';
|
|
|
|
import * as IconGrid from './iconGrid.js';
|
|
|
|
import * as Main from './main.js';
|
|
|
|
import * as Overview from './overview.js';
|
|
|
|
|
|
|
|
const DASH_ANIMATION_TIME = 200;
|
|
|
|
const DASH_ITEM_LABEL_SHOW_TIME = 150;
|
|
|
|
const DASH_ITEM_LABEL_HIDE_TIME = 100;
|
|
|
|
const DASH_ITEM_HOVER_TIMEOUT = 300;
|
2011-01-21 11:06:13 +00:00
|
|
|
|
2023-07-10 09:53:00 +00:00
|
|
|
export const DashIcon = GObject.registerClass(
|
2019-07-16 09:24:13 +00:00
|
|
|
class DashIcon extends AppDisplay.AppIcon {
|
|
|
|
_init(app) {
|
|
|
|
super._init(app, {
|
2019-07-12 22:32:54 +00:00
|
|
|
setSizeManually: true,
|
2019-08-20 21:43:54 +00:00
|
|
|
showLabel: false,
|
2019-07-12 22:32:54 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-01-07 13:05:18 +00:00
|
|
|
popupMenu() {
|
|
|
|
super.popupMenu(St.Side.BOTTOM);
|
|
|
|
}
|
|
|
|
|
2020-10-02 15:10:42 +00:00
|
|
|
// Disable scale-n-fade methods used during DND by parent
|
|
|
|
scaleAndFade() {
|
2019-07-12 22:32:54 +00:00
|
|
|
}
|
|
|
|
|
2020-10-02 15:10:42 +00:00
|
|
|
undoScaleAndFade() {
|
2019-07-12 22:32:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
handleDragOver() {
|
|
|
|
return DND.DragMotionResult.CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
acceptDrop() {
|
|
|
|
return false;
|
|
|
|
}
|
2019-07-16 09:24:13 +00:00
|
|
|
});
|
2019-07-12 22:32:54 +00:00
|
|
|
|
2011-01-20 15:23:43 +00:00
|
|
|
// A container like StBin, but taking the child's scale into account
|
|
|
|
// when requesting a size
|
2023-07-10 09:53:00 +00:00
|
|
|
export const DashItemContainer = GObject.registerClass(
|
2017-10-31 01:23:39 +00:00
|
|
|
class DashItemContainer extends St.Widget {
|
2017-10-31 00:03:21 +00:00
|
|
|
_init() {
|
2021-02-09 21:01:45 +00:00
|
|
|
super._init({
|
|
|
|
style_class: 'dash-item-container',
|
2023-08-06 22:40:20 +00:00
|
|
|
pivot_point: new Graphene.Point({x: .5, y: .5}),
|
2021-02-09 18:57:55 +00:00
|
|
|
layout_manager: new Clutter.BinLayout(),
|
2021-02-09 21:01:45 +00:00
|
|
|
scale_x: 0,
|
|
|
|
scale_y: 0,
|
|
|
|
opacity: 0,
|
|
|
|
x_expand: true,
|
|
|
|
x_align: Clutter.ActorAlign.CENTER,
|
|
|
|
});
|
2011-01-20 15:23:43 +00:00
|
|
|
|
2023-08-06 22:34:20 +00:00
|
|
|
this._labelText = '';
|
2023-08-06 22:40:20 +00:00
|
|
|
this.label = new St.Label({style_class: 'dash-label'});
|
2012-10-03 05:19:36 +00:00
|
|
|
this.label.hide();
|
|
|
|
Main.layoutManager.addChrome(this.label);
|
2023-04-17 17:53:34 +00:00
|
|
|
this.label.connectObject('destroy', () => (this.label = null), this);
|
2012-12-22 13:57:06 +00:00
|
|
|
this.label_actor = this.label;
|
2011-12-16 22:46:07 +00:00
|
|
|
|
2011-01-20 15:23:43 +00:00
|
|
|
this.child = null;
|
2011-09-19 21:47:16 +00:00
|
|
|
this.animatingOut = false;
|
2017-12-05 22:04:24 +00:00
|
|
|
|
2018-07-21 05:08:33 +00:00
|
|
|
this.connect('notify::scale-x', () => this.queue_relayout());
|
|
|
|
this.connect('notify::scale-y', () => this.queue_relayout());
|
|
|
|
|
2017-12-05 22:04:24 +00:00
|
|
|
this.connect('destroy', () => {
|
2018-11-16 18:31:56 +00:00
|
|
|
if (this.child != null)
|
|
|
|
this.child.destroy();
|
2023-04-17 17:53:34 +00:00
|
|
|
this.label?.destroy();
|
2017-12-05 22:04:24 +00:00
|
|
|
});
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2011-01-20 15:23:43 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
vfunc_get_preferred_height(forWidth) {
|
2012-12-22 13:57:06 +00:00
|
|
|
let themeNode = this.get_theme_node();
|
|
|
|
forWidth = themeNode.adjust_for_width(forWidth);
|
2017-10-31 01:23:39 +00:00
|
|
|
let [minHeight, natHeight] = super.vfunc_get_preferred_height(forWidth);
|
2023-08-06 23:45:22 +00:00
|
|
|
return themeNode.adjust_preferred_height(
|
|
|
|
minHeight * this.scale_y,
|
|
|
|
natHeight * this.scale_y);
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2011-01-20 15:23:43 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
vfunc_get_preferred_width(forHeight) {
|
2012-12-22 13:57:06 +00:00
|
|
|
let themeNode = this.get_theme_node();
|
|
|
|
forHeight = themeNode.adjust_for_height(forHeight);
|
2017-10-31 01:23:39 +00:00
|
|
|
let [minWidth, natWidth] = super.vfunc_get_preferred_width(forHeight);
|
2023-08-06 23:45:22 +00:00
|
|
|
return themeNode.adjust_preferred_width(
|
|
|
|
minWidth * this.scale_x,
|
|
|
|
natWidth * this.scale_x);
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2011-01-20 15:23:43 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
showLabel() {
|
2012-10-03 05:22:46 +00:00
|
|
|
if (!this._labelText)
|
|
|
|
return;
|
|
|
|
|
|
|
|
this.label.set_text(this._labelText);
|
2012-03-15 19:18:53 +00:00
|
|
|
this.label.opacity = 0;
|
|
|
|
this.label.show();
|
2011-12-16 22:46:07 +00:00
|
|
|
|
2012-12-22 13:57:06 +00:00
|
|
|
let [stageX, stageY] = this.get_transformed_position();
|
2011-12-16 22:46:07 +00:00
|
|
|
|
2020-12-11 12:47:28 +00:00
|
|
|
const itemWidth = this.allocation.get_width();
|
2011-12-16 22:46:07 +00:00
|
|
|
|
2020-12-11 12:47:28 +00:00
|
|
|
const labelWidth = this.label.get_width();
|
|
|
|
const xOffset = Math.floor((itemWidth - labelWidth) / 2);
|
|
|
|
const x = Math.clamp(stageX + xOffset, 0, global.stage.width - labelWidth);
|
2011-12-16 22:46:07 +00:00
|
|
|
|
2012-03-15 19:18:53 +00:00
|
|
|
let node = this.label.get_theme_node();
|
2020-12-11 12:47:28 +00:00
|
|
|
const yOffset = node.get_length('-y-offset');
|
2011-12-16 22:46:07 +00:00
|
|
|
|
2020-12-11 12:47:28 +00:00
|
|
|
const y = stageY - this.label.height - yOffset;
|
2011-12-16 22:46:07 +00:00
|
|
|
|
2012-03-15 19:18:53 +00:00
|
|
|
this.label.set_position(x, y);
|
2018-07-20 19:46:19 +00:00
|
|
|
this.label.ease({
|
|
|
|
opacity: 255,
|
|
|
|
duration: DASH_ITEM_LABEL_SHOW_TIME,
|
2019-08-20 21:43:54 +00:00
|
|
|
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
2018-07-20 19:46:19 +00:00
|
|
|
});
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2011-12-16 22:46:07 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
setLabelText(text) {
|
2012-10-03 05:22:46 +00:00
|
|
|
this._labelText = text;
|
2012-10-24 17:29:07 +00:00
|
|
|
this.child.accessible_name = text;
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2011-12-16 22:46:07 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
hideLabel() {
|
2018-07-20 19:46:19 +00:00
|
|
|
this.label.ease({
|
|
|
|
opacity: 0,
|
|
|
|
duration: DASH_ITEM_LABEL_HIDE_TIME,
|
|
|
|
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
2019-08-20 21:43:54 +00:00
|
|
|
onComplete: () => this.label.hide(),
|
2018-07-20 19:46:19 +00:00
|
|
|
});
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2011-12-16 22:46:07 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
setChild(actor) {
|
2023-08-07 00:51:19 +00:00
|
|
|
if (this.child === actor)
|
2011-01-20 15:23:43 +00:00
|
|
|
return;
|
|
|
|
|
2012-12-22 13:57:06 +00:00
|
|
|
this.destroy_all_children();
|
2011-01-20 15:23:43 +00:00
|
|
|
|
|
|
|
this.child = actor;
|
2021-02-09 18:57:55 +00:00
|
|
|
this.child.y_expand = true;
|
2012-12-22 13:57:06 +00:00
|
|
|
this.add_actor(this.child);
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2011-01-21 11:06:13 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
show(animate) {
|
2011-01-21 11:06:13 +00:00
|
|
|
if (this.child == null)
|
|
|
|
return;
|
|
|
|
|
2012-12-22 14:26:12 +00:00
|
|
|
let time = animate ? DASH_ANIMATION_TIME : 0;
|
2018-07-20 19:46:19 +00:00
|
|
|
this.ease({
|
|
|
|
scale_x: 1,
|
|
|
|
scale_y: 1,
|
|
|
|
opacity: 255,
|
|
|
|
duration: time,
|
2019-08-20 21:43:54 +00:00
|
|
|
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
2018-07-20 19:46:19 +00:00
|
|
|
});
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2011-01-21 11:06:13 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
animateOutAndDestroy() {
|
2017-12-05 01:45:35 +00:00
|
|
|
this.label.hide();
|
2012-04-08 19:35:41 +00:00
|
|
|
|
2011-01-21 11:06:13 +00:00
|
|
|
if (this.child == null) {
|
2012-12-22 13:57:06 +00:00
|
|
|
this.destroy();
|
2011-01-21 11:06:13 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-09-19 21:47:16 +00:00
|
|
|
this.animatingOut = true;
|
2018-07-20 19:46:19 +00:00
|
|
|
this.ease({
|
|
|
|
scale_x: 0,
|
|
|
|
scale_y: 0,
|
|
|
|
opacity: 0,
|
|
|
|
duration: DASH_ANIMATION_TIME,
|
|
|
|
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
2019-08-20 21:43:54 +00:00
|
|
|
onComplete: () => this.destroy(),
|
2018-07-20 19:46:19 +00:00
|
|
|
});
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2011-11-20 16:07:14 +00:00
|
|
|
});
|
2010-11-08 01:51:02 +00:00
|
|
|
|
2023-07-10 09:53:00 +00:00
|
|
|
export const ShowAppsIcon = GObject.registerClass(
|
2017-10-31 01:23:39 +00:00
|
|
|
class ShowAppsIcon extends DashItemContainer {
|
2017-10-31 00:03:21 +00:00
|
|
|
_init() {
|
2017-10-31 01:23:39 +00:00
|
|
|
super._init();
|
2011-01-20 15:23:43 +00:00
|
|
|
|
2020-03-29 21:51:13 +00:00
|
|
|
this.toggleButton = new St.Button({
|
|
|
|
style_class: 'show-apps',
|
|
|
|
track_hover: true,
|
|
|
|
can_focus: true,
|
|
|
|
toggle_mode: true,
|
|
|
|
});
|
2010-11-08 01:51:02 +00:00
|
|
|
this._iconActor = null;
|
2022-12-16 21:33:10 +00:00
|
|
|
this.icon = new IconGrid.BaseIcon(_('Show Apps'), {
|
2020-03-29 21:51:13 +00:00
|
|
|
setSizeManually: true,
|
|
|
|
showLabel: false,
|
|
|
|
createIcon: this._createIcon.bind(this),
|
|
|
|
});
|
2021-02-09 18:57:55 +00:00
|
|
|
this.icon.y_align = Clutter.ActorAlign.CENTER;
|
|
|
|
|
2018-06-30 18:00:08 +00:00
|
|
|
this.toggleButton.add_actor(this.icon);
|
2012-07-22 12:45:53 +00:00
|
|
|
this.toggleButton._delegate = this;
|
2011-01-20 15:23:43 +00:00
|
|
|
|
2012-07-22 12:45:53 +00:00
|
|
|
this.setChild(this.toggleButton);
|
2012-10-03 05:17:07 +00:00
|
|
|
this.setDragApp(null);
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2010-11-08 01:51:02 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_createIcon(size) {
|
2020-03-29 21:51:13 +00:00
|
|
|
this._iconActor = new St.Icon({
|
|
|
|
icon_name: 'view-app-grid-symbolic',
|
|
|
|
icon_size: size,
|
|
|
|
style_class: 'show-apps-icon',
|
|
|
|
track_hover: true,
|
|
|
|
});
|
2010-11-08 01:51:02 +00:00
|
|
|
return this._iconActor;
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2010-11-08 01:51:02 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_canRemoveApp(app) {
|
2012-10-03 05:17:07 +00:00
|
|
|
if (app == null)
|
|
|
|
return false;
|
|
|
|
|
2015-03-20 19:56:52 +00:00
|
|
|
if (!global.settings.is_writable('favorite-apps'))
|
2014-12-11 15:22:19 +00:00
|
|
|
return false;
|
|
|
|
|
2012-10-03 05:17:07 +00:00
|
|
|
let id = app.get_id();
|
|
|
|
let isFavorite = AppFavorites.getAppFavorites().isFavorite(id);
|
|
|
|
return isFavorite;
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2012-10-03 05:17:07 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
setDragApp(app) {
|
2012-10-03 05:17:07 +00:00
|
|
|
let canRemove = this._canRemoveApp(app);
|
|
|
|
|
|
|
|
this.toggleButton.set_hover(canRemove);
|
2010-11-08 01:51:02 +00:00
|
|
|
if (this._iconActor)
|
2012-10-03 05:17:07 +00:00
|
|
|
this._iconActor.set_hover(canRemove);
|
2012-08-22 09:46:28 +00:00
|
|
|
|
2012-10-03 05:17:07 +00:00
|
|
|
if (canRemove)
|
2022-01-29 17:07:25 +00:00
|
|
|
this.setLabelText(_('Unpin'));
|
2012-08-22 09:46:28 +00:00
|
|
|
else
|
2022-12-16 21:33:10 +00:00
|
|
|
this.setLabelText(_('Show Apps'));
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2010-11-08 01:51:02 +00:00
|
|
|
|
2019-01-31 14:08:10 +00:00
|
|
|
handleDragOver(source, _actor, _x, _y, _time) {
|
2023-08-19 16:31:24 +00:00
|
|
|
if (!this._canRemoveApp(Dash.getAppFromSource(source)))
|
2012-10-02 23:53:07 +00:00
|
|
|
return DND.DragMotionResult.NO_DROP;
|
|
|
|
|
2010-11-08 01:51:02 +00:00
|
|
|
return DND.DragMotionResult.MOVE_DROP;
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2010-11-08 01:51:02 +00:00
|
|
|
|
2019-01-31 14:08:10 +00:00
|
|
|
acceptDrop(source, _actor, _x, _y, _time) {
|
2023-08-19 16:31:24 +00:00
|
|
|
const app = Dash.getAppFromSource(source);
|
2013-05-31 18:00:17 +00:00
|
|
|
if (!this._canRemoveApp(app))
|
2012-10-03 00:13:47 +00:00
|
|
|
return false;
|
2010-11-08 01:51:02 +00:00
|
|
|
|
|
|
|
let id = app.get_id();
|
|
|
|
|
2022-09-07 18:23:38 +00:00
|
|
|
const laters = global.compositor.get_laters();
|
|
|
|
laters.add(Meta.LaterType.BEFORE_REDRAW, () => {
|
2017-10-31 00:38:18 +00:00
|
|
|
AppFavorites.getAppFavorites().removeFavorite(id);
|
|
|
|
return false;
|
|
|
|
});
|
2010-11-08 01:51:02 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2011-11-20 16:07:14 +00:00
|
|
|
});
|
2010-11-08 01:51:02 +00:00
|
|
|
|
2023-07-10 09:53:00 +00:00
|
|
|
const DragPlaceholderItem = GObject.registerClass(
|
2017-10-31 01:23:39 +00:00
|
|
|
class DragPlaceholderItem extends DashItemContainer {
|
2017-10-31 00:03:21 +00:00
|
|
|
_init() {
|
2017-10-31 01:23:39 +00:00
|
|
|
super._init();
|
2023-08-06 22:40:20 +00:00
|
|
|
this.setChild(new St.Bin({style_class: 'placeholder'}));
|
2011-01-20 15:23:43 +00:00
|
|
|
}
|
2011-11-20 16:07:14 +00:00
|
|
|
});
|
2011-01-20 15:23:43 +00:00
|
|
|
|
2023-07-10 09:53:00 +00:00
|
|
|
const EmptyDropTargetItem = GObject.registerClass(
|
2017-10-31 01:23:39 +00:00
|
|
|
class EmptyDropTargetItem extends DashItemContainer {
|
2017-10-31 00:03:21 +00:00
|
|
|
_init() {
|
2017-10-31 01:23:39 +00:00
|
|
|
super._init();
|
2023-08-06 22:40:20 +00:00
|
|
|
this.setChild(new St.Bin({style_class: 'empty-dash-drop-target'}));
|
2013-05-31 15:59:27 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2021-01-19 16:34:19 +00:00
|
|
|
const DashIconsLayout = GObject.registerClass(
|
|
|
|
class DashIconsLayout extends Clutter.BoxLayout {
|
2017-10-31 00:03:21 +00:00
|
|
|
_init() {
|
2019-10-17 21:40:24 +00:00
|
|
|
super._init({
|
2021-01-19 16:34:19 +00:00
|
|
|
orientation: Clutter.Orientation.HORIZONTAL,
|
2019-10-17 21:40:24 +00:00
|
|
|
});
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2012-09-10 18:42:08 +00:00
|
|
|
|
2021-01-19 16:34:19 +00:00
|
|
|
vfunc_get_preferred_width(container, forHeight) {
|
|
|
|
const [, natWidth] = super.vfunc_get_preferred_width(container, forHeight);
|
|
|
|
return [0, natWidth];
|
2012-09-10 18:42:08 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2019-01-29 01:27:05 +00:00
|
|
|
const baseIconSizes = [16, 22, 24, 32, 48, 64];
|
2014-02-16 05:35:13 +00:00
|
|
|
|
2023-07-10 09:53:00 +00:00
|
|
|
export const Dash = GObject.registerClass({
|
2023-08-06 22:40:20 +00:00
|
|
|
Signals: {'icon-size-changed': {}},
|
2021-02-09 18:57:55 +00:00
|
|
|
}, class Dash extends St.Widget {
|
2023-08-19 16:31:24 +00:00
|
|
|
/**
|
|
|
|
* @param {object} source
|
|
|
|
*/
|
|
|
|
static getAppFromSource(source) {
|
|
|
|
if (source instanceof AppDisplay.AppIcon)
|
|
|
|
return source.app;
|
|
|
|
else
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2019-07-16 09:24:13 +00:00
|
|
|
_init() {
|
2020-12-11 12:47:28 +00:00
|
|
|
this._maxWidth = -1;
|
2021-01-22 13:36:37 +00:00
|
|
|
this._maxHeight = -1;
|
2011-02-12 00:17:10 +00:00
|
|
|
this.iconSize = 64;
|
2011-02-02 15:44:07 +00:00
|
|
|
this._shownInitially = false;
|
2010-11-08 01:51:02 +00:00
|
|
|
|
2021-01-28 22:24:44 +00:00
|
|
|
this._separator = null;
|
2010-11-08 01:51:02 +00:00
|
|
|
this._dragPlaceholder = null;
|
|
|
|
this._dragPlaceholderPos = -1;
|
2011-01-21 11:06:13 +00:00
|
|
|
this._animatingPlaceholdersCount = 0;
|
2012-11-06 23:33:32 +00:00
|
|
|
this._showLabelTimeoutId = 0;
|
2012-01-20 15:14:16 +00:00
|
|
|
this._resetHoverTimeoutId = 0;
|
2012-11-06 23:33:32 +00:00
|
|
|
this._labelShowing = false;
|
2010-07-21 23:29:02 +00:00
|
|
|
|
2021-01-19 16:34:19 +00:00
|
|
|
super._init({
|
|
|
|
name: 'dash',
|
|
|
|
offscreen_redirect: Clutter.OffscreenRedirect.ALWAYS,
|
2021-02-09 18:57:55 +00:00
|
|
|
layout_manager: new Clutter.BinLayout(),
|
|
|
|
});
|
|
|
|
|
|
|
|
this._dashContainer = new St.BoxLayout({
|
2021-01-19 16:34:19 +00:00
|
|
|
x_align: Clutter.ActorAlign.CENTER,
|
2021-02-09 18:57:55 +00:00
|
|
|
y_expand: true,
|
2021-01-19 16:34:19 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
this._box = new St.Widget({
|
|
|
|
clip_to_allocation: true,
|
|
|
|
layout_manager: new DashIconsLayout(),
|
2021-02-09 18:57:55 +00:00
|
|
|
y_expand: true,
|
2021-01-19 16:34:19 +00:00
|
|
|
});
|
2010-07-21 23:29:02 +00:00
|
|
|
this._box._delegate = this;
|
2021-02-09 18:57:55 +00:00
|
|
|
|
|
|
|
this._dashContainer.add_child(this._box);
|
2012-08-14 14:27:28 +00:00
|
|
|
|
2012-08-14 14:34:14 +00:00
|
|
|
this._showAppsIcon = new ShowAppsIcon();
|
2018-07-21 05:08:33 +00:00
|
|
|
this._showAppsIcon.show(false);
|
2012-08-14 14:34:14 +00:00
|
|
|
this._showAppsIcon.icon.setIconSize(this.iconSize);
|
2012-11-06 23:33:32 +00:00
|
|
|
this._hookUpLabel(this._showAppsIcon);
|
2021-02-09 18:57:55 +00:00
|
|
|
this._dashContainer.add_child(this._showAppsIcon);
|
2012-08-14 14:27:28 +00:00
|
|
|
|
2012-07-22 12:45:53 +00:00
|
|
|
this.showAppsButton = this._showAppsIcon.toggleButton;
|
|
|
|
|
2021-01-22 13:36:37 +00:00
|
|
|
this._background = new St.Widget({
|
2021-02-09 18:57:55 +00:00
|
|
|
style_class: 'dash-background',
|
|
|
|
});
|
|
|
|
|
|
|
|
const sizerBox = new Clutter.Actor();
|
|
|
|
sizerBox.add_constraint(new Clutter.BindConstraint({
|
|
|
|
source: this._showAppsIcon.icon,
|
|
|
|
coordinate: Clutter.BindCoordinate.HEIGHT,
|
|
|
|
}));
|
|
|
|
sizerBox.add_constraint(new Clutter.BindConstraint({
|
|
|
|
source: this._dashContainer,
|
|
|
|
coordinate: Clutter.BindCoordinate.WIDTH,
|
|
|
|
}));
|
2021-01-22 13:36:37 +00:00
|
|
|
this._background.add_child(sizerBox);
|
2021-02-09 18:57:55 +00:00
|
|
|
|
2021-01-22 13:36:37 +00:00
|
|
|
this.add_child(this._background);
|
2021-02-09 18:57:55 +00:00
|
|
|
this.add_child(this._dashContainer);
|
|
|
|
|
2017-12-02 00:27:35 +00:00
|
|
|
this._workId = Main.initializeDeferredWork(this._box, this._redisplay.bind(this));
|
2010-07-21 23:29:02 +00:00
|
|
|
|
|
|
|
this._appSystem = Shell.AppSystem.get_default();
|
|
|
|
|
2017-10-31 00:38:18 +00:00
|
|
|
this._appSystem.connect('installed-changed', () => {
|
2013-08-27 12:00:26 +00:00
|
|
|
AppFavorites.getAppFavorites().reload();
|
2013-08-31 17:52:21 +00:00
|
|
|
this._queueRedisplay();
|
2017-10-31 00:38:18 +00:00
|
|
|
});
|
2017-12-02 00:27:35 +00:00
|
|
|
AppFavorites.getAppFavorites().connect('changed', this._queueRedisplay.bind(this));
|
|
|
|
this._appSystem.connect('app-state-changed', this._queueRedisplay.bind(this));
|
2010-11-08 01:51:02 +00:00
|
|
|
|
2011-02-11 23:01:59 +00:00
|
|
|
Main.overview.connect('item-drag-begin',
|
2021-02-09 16:50:29 +00:00
|
|
|
this._onItemDragBegin.bind(this));
|
2011-02-11 23:01:59 +00:00
|
|
|
Main.overview.connect('item-drag-end',
|
2021-02-09 16:50:29 +00:00
|
|
|
this._onItemDragEnd.bind(this));
|
2011-03-09 15:56:08 +00:00
|
|
|
Main.overview.connect('item-drag-cancelled',
|
2021-02-09 16:50:29 +00:00
|
|
|
this._onItemDragCancelled.bind(this));
|
|
|
|
Main.overview.connect('window-drag-begin',
|
|
|
|
this._onWindowDragBegin.bind(this));
|
|
|
|
Main.overview.connect('window-drag-cancelled',
|
|
|
|
this._onWindowDragEnd.bind(this));
|
|
|
|
Main.overview.connect('window-drag-end',
|
|
|
|
this._onWindowDragEnd.bind(this));
|
2013-02-15 23:23:15 +00:00
|
|
|
|
|
|
|
// Translators: this is the name of the dock/favorites area on
|
|
|
|
// the left of the overview
|
2023-08-06 22:34:20 +00:00
|
|
|
Main.ctrlAltTabManager.addGroup(this, _('Dash'), 'user-bookmarks-symbolic');
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2010-11-08 01:51:02 +00:00
|
|
|
|
2021-02-09 16:50:29 +00:00
|
|
|
_onItemDragBegin() {
|
2011-03-09 15:56:08 +00:00
|
|
|
this._dragCancelled = false;
|
2010-11-08 01:51:02 +00:00
|
|
|
this._dragMonitor = {
|
2021-02-09 16:50:29 +00:00
|
|
|
dragMotion: this._onItemDragMotion.bind(this),
|
2010-11-08 01:51:02 +00:00
|
|
|
};
|
|
|
|
DND.addDragMonitor(this._dragMonitor);
|
2013-05-31 15:59:27 +00:00
|
|
|
|
2023-08-07 00:51:19 +00:00
|
|
|
if (this._box.get_n_children() === 0) {
|
2013-05-31 15:59:27 +00:00
|
|
|
this._emptyDropTarget = new EmptyDropTargetItem();
|
|
|
|
this._box.insert_child_at_index(this._emptyDropTarget, 0);
|
|
|
|
this._emptyDropTarget.show(true);
|
|
|
|
}
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2010-11-08 01:51:02 +00:00
|
|
|
|
2021-02-09 16:50:29 +00:00
|
|
|
_onItemDragCancelled() {
|
2011-03-09 15:56:08 +00:00
|
|
|
this._dragCancelled = true;
|
2021-02-09 16:50:29 +00:00
|
|
|
this._endItemDrag();
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2011-03-09 15:56:08 +00:00
|
|
|
|
2021-02-09 16:50:29 +00:00
|
|
|
_onItemDragEnd() {
|
2011-03-09 15:56:08 +00:00
|
|
|
if (this._dragCancelled)
|
|
|
|
return;
|
|
|
|
|
2021-02-09 16:50:29 +00:00
|
|
|
this._endItemDrag();
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2011-03-09 15:56:08 +00:00
|
|
|
|
2021-02-09 16:50:29 +00:00
|
|
|
_endItemDrag() {
|
2010-11-08 01:51:02 +00:00
|
|
|
this._clearDragPlaceholder();
|
2013-05-31 15:59:27 +00:00
|
|
|
this._clearEmptyDropTarget();
|
2012-10-08 18:33:21 +00:00
|
|
|
this._showAppsIcon.setDragApp(null);
|
2011-06-27 16:59:56 +00:00
|
|
|
DND.removeDragMonitor(this._dragMonitor);
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2010-11-08 01:51:02 +00:00
|
|
|
|
2021-02-09 16:50:29 +00:00
|
|
|
_onItemDragMotion(dragEvent) {
|
2023-08-19 16:31:24 +00:00
|
|
|
const app = Dash.getAppFromSource(dragEvent.source);
|
2012-10-03 00:13:47 +00:00
|
|
|
if (app == null)
|
2010-11-08 01:51:02 +00:00
|
|
|
return DND.DragMotionResult.CONTINUE;
|
|
|
|
|
2012-08-14 14:34:14 +00:00
|
|
|
let showAppsHovered =
|
2012-12-22 13:57:06 +00:00
|
|
|
this._showAppsIcon.contains(dragEvent.targetActor);
|
2010-11-08 01:51:02 +00:00
|
|
|
|
2012-08-14 14:34:14 +00:00
|
|
|
if (!this._box.contains(dragEvent.targetActor) || showAppsHovered)
|
2010-11-08 01:51:02 +00:00
|
|
|
this._clearDragPlaceholder();
|
|
|
|
|
2012-10-03 05:17:07 +00:00
|
|
|
if (showAppsHovered)
|
|
|
|
this._showAppsIcon.setDragApp(app);
|
|
|
|
else
|
|
|
|
this._showAppsIcon.setDragApp(null);
|
2010-11-08 01:51:02 +00:00
|
|
|
|
|
|
|
return DND.DragMotionResult.CONTINUE;
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2010-11-08 01:51:02 +00:00
|
|
|
|
2021-02-09 16:50:29 +00:00
|
|
|
_onWindowDragBegin() {
|
|
|
|
this.ease({
|
|
|
|
opacity: 128,
|
|
|
|
duration: Overview.ANIMATION_TIME / 2,
|
|
|
|
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
_onWindowDragEnd() {
|
|
|
|
this.ease({
|
|
|
|
opacity: 255,
|
|
|
|
duration: Overview.ANIMATION_TIME / 2,
|
|
|
|
mode: Clutter.AnimationMode.EASE_IN_QUAD,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_appIdListToHash(apps) {
|
2012-11-06 23:33:32 +00:00
|
|
|
let ids = {};
|
|
|
|
for (let i = 0; i < apps.length; i++)
|
|
|
|
ids[apps[i].get_id()] = apps[i];
|
|
|
|
return ids;
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-11-06 23:33:32 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_queueRedisplay() {
|
2010-07-21 23:29:02 +00:00
|
|
|
Main.queueDeferredWork(this._workId);
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2010-07-21 23:29:02 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_hookUpLabel(item, appIcon) {
|
2017-10-31 00:38:18 +00:00
|
|
|
item.child.connect('notify::hover', () => {
|
2013-08-18 14:20:22 +00:00
|
|
|
this._syncLabel(item, appIcon);
|
2017-10-31 00:38:18 +00:00
|
|
|
});
|
2012-11-06 23:33:32 +00:00
|
|
|
|
2020-08-27 08:52:14 +00:00
|
|
|
item.child.connect('clicked', () => {
|
|
|
|
this._labelShowing = false;
|
|
|
|
item.hideLabel();
|
|
|
|
});
|
|
|
|
|
2021-08-15 22:36:59 +00:00
|
|
|
Main.overview.connectObject('hiding', () => {
|
2012-11-06 23:33:32 +00:00
|
|
|
this._labelShowing = false;
|
|
|
|
item.hideLabel();
|
2021-08-15 22:36:59 +00:00
|
|
|
}, item.child);
|
2013-08-18 14:20:22 +00:00
|
|
|
|
|
|
|
if (appIcon) {
|
2017-10-31 00:38:18 +00:00
|
|
|
appIcon.connect('sync-tooltip', () => {
|
2013-08-18 14:20:22 +00:00
|
|
|
this._syncLabel(item, appIcon);
|
2017-10-31 00:38:18 +00:00
|
|
|
});
|
2013-08-18 14:20:22 +00:00
|
|
|
}
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-08-22 09:46:28 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_createAppItem(app) {
|
2019-07-12 22:32:54 +00:00
|
|
|
let appIcon = new DashIcon(app);
|
2015-01-27 21:10:45 +00:00
|
|
|
|
2023-08-06 23:45:22 +00:00
|
|
|
appIcon.connect('menu-state-changed', (o, opened) => {
|
|
|
|
this._itemMenuStateChanged(item, opened);
|
|
|
|
});
|
2011-02-10 00:41:51 +00:00
|
|
|
|
2011-01-20 15:23:43 +00:00
|
|
|
let item = new DashItemContainer();
|
2019-07-16 09:24:13 +00:00
|
|
|
item.setChild(appIcon);
|
2011-01-20 15:23:43 +00:00
|
|
|
|
2013-01-30 22:51:43 +00:00
|
|
|
// Override default AppIcon label_actor, now the
|
2012-10-24 17:29:07 +00:00
|
|
|
// accessible_name is set at DashItemContainer.setLabelText
|
2019-07-16 09:24:13 +00:00
|
|
|
appIcon.label_actor = null;
|
2011-12-16 22:46:07 +00:00
|
|
|
item.setLabelText(app.get_name());
|
2012-10-24 17:29:07 +00:00
|
|
|
|
2012-11-03 20:03:49 +00:00
|
|
|
appIcon.icon.setIconSize(this.iconSize);
|
2013-08-18 14:20:22 +00:00
|
|
|
this._hookUpLabel(item, appIcon);
|
2012-04-16 15:04:29 +00:00
|
|
|
|
2011-01-20 15:23:43 +00:00
|
|
|
return item;
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2010-11-08 01:51:02 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_itemMenuStateChanged(item, opened) {
|
2012-11-03 20:03:33 +00:00
|
|
|
// When the menu closes, it calls sync_hover, which means
|
|
|
|
// that the notify::hover handler does everything we need to.
|
|
|
|
if (opened) {
|
2012-11-06 23:33:32 +00:00
|
|
|
if (this._showLabelTimeoutId > 0) {
|
2019-08-19 18:50:33 +00:00
|
|
|
GLib.source_remove(this._showLabelTimeoutId);
|
2012-11-06 23:33:32 +00:00
|
|
|
this._showLabelTimeoutId = 0;
|
2012-11-03 20:03:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
item.hideLabel();
|
|
|
|
}
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-11-03 20:03:33 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_syncLabel(item, appIcon) {
|
2013-08-18 14:20:22 +00:00
|
|
|
let shouldShow = appIcon ? appIcon.shouldShowTooltip() : item.child.get_hover();
|
|
|
|
|
|
|
|
if (shouldShow) {
|
2023-08-07 00:51:19 +00:00
|
|
|
if (this._showLabelTimeoutId === 0) {
|
2012-11-06 23:33:32 +00:00
|
|
|
let timeout = this._labelShowing ? 0 : DASH_ITEM_HOVER_TIMEOUT;
|
2019-08-19 18:50:33 +00:00
|
|
|
this._showLabelTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, timeout,
|
2017-10-31 00:38:18 +00:00
|
|
|
() => {
|
2012-11-06 23:33:32 +00:00
|
|
|
this._labelShowing = true;
|
2011-12-16 22:46:07 +00:00
|
|
|
item.showLabel();
|
2013-11-09 16:11:01 +00:00
|
|
|
this._showLabelTimeoutId = 0;
|
2013-11-29 00:45:39 +00:00
|
|
|
return GLib.SOURCE_REMOVE;
|
2017-10-31 00:38:18 +00:00
|
|
|
});
|
2014-04-10 17:26:52 +00:00
|
|
|
GLib.Source.set_name_by_id(this._showLabelTimeoutId, '[gnome-shell] item.showLabel');
|
2012-01-20 15:14:16 +00:00
|
|
|
if (this._resetHoverTimeoutId > 0) {
|
2019-08-19 18:50:33 +00:00
|
|
|
GLib.source_remove(this._resetHoverTimeoutId);
|
2012-04-16 15:04:29 +00:00
|
|
|
this._resetHoverTimeoutId = 0;
|
2012-01-20 15:14:16 +00:00
|
|
|
}
|
2011-12-16 22:46:07 +00:00
|
|
|
}
|
|
|
|
} else {
|
2012-11-06 23:33:32 +00:00
|
|
|
if (this._showLabelTimeoutId > 0)
|
2019-08-19 18:50:33 +00:00
|
|
|
GLib.source_remove(this._showLabelTimeoutId);
|
2012-11-06 23:33:32 +00:00
|
|
|
this._showLabelTimeoutId = 0;
|
2011-12-16 22:46:07 +00:00
|
|
|
item.hideLabel();
|
2012-11-06 23:33:32 +00:00
|
|
|
if (this._labelShowing) {
|
2019-08-19 18:50:33 +00:00
|
|
|
this._resetHoverTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, DASH_ITEM_HOVER_TIMEOUT,
|
2017-10-31 00:38:18 +00:00
|
|
|
() => {
|
2012-11-06 23:33:32 +00:00
|
|
|
this._labelShowing = false;
|
2013-11-09 16:11:01 +00:00
|
|
|
this._resetHoverTimeoutId = 0;
|
2013-11-29 00:45:39 +00:00
|
|
|
return GLib.SOURCE_REMOVE;
|
2017-10-31 00:38:18 +00:00
|
|
|
});
|
2014-04-10 17:26:52 +00:00
|
|
|
GLib.Source.set_name_by_id(this._resetHoverTimeoutId, '[gnome-shell] this._labelShowing');
|
2012-01-20 15:14:16 +00:00
|
|
|
}
|
2011-12-16 22:46:07 +00:00
|
|
|
}
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2011-12-16 22:46:07 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_adjustIconSize() {
|
2011-09-20 15:59:25 +00:00
|
|
|
// For the icon size, we only consider children which are "proper"
|
|
|
|
// icons (i.e. ignoring drag placeholders) and which are not
|
|
|
|
// animating out (which means they will be destroyed at the end of
|
|
|
|
// the animation)
|
2017-10-31 00:38:18 +00:00
|
|
|
let iconChildren = this._box.get_children().filter(actor => {
|
2012-12-22 13:57:06 +00:00
|
|
|
return actor.child &&
|
|
|
|
actor.child._delegate &&
|
|
|
|
actor.child._delegate.icon &&
|
|
|
|
!actor.animatingOut;
|
2011-09-20 15:59:25 +00:00
|
|
|
});
|
|
|
|
|
2012-12-22 13:57:06 +00:00
|
|
|
iconChildren.push(this._showAppsIcon);
|
2010-11-27 21:31:14 +00:00
|
|
|
|
2021-01-22 13:36:37 +00:00
|
|
|
if (this._maxWidth === -1 || this._maxHeight === -1)
|
2010-11-27 21:31:14 +00:00
|
|
|
return;
|
|
|
|
|
2021-01-19 16:34:19 +00:00
|
|
|
const themeNode = this.get_theme_node();
|
2020-12-11 12:47:28 +00:00
|
|
|
const maxAllocation = new Clutter.ActorBox({
|
|
|
|
x1: 0,
|
|
|
|
y1: 0,
|
|
|
|
x2: this._maxWidth,
|
|
|
|
y2: 42, /* whatever */
|
|
|
|
});
|
2011-09-20 15:59:25 +00:00
|
|
|
let maxContent = themeNode.get_content_box(maxAllocation);
|
2020-12-11 12:47:28 +00:00
|
|
|
let availWidth = maxContent.x2 - maxContent.x1;
|
2011-09-20 15:59:25 +00:00
|
|
|
let spacing = themeNode.get_length('spacing');
|
2011-09-19 21:47:16 +00:00
|
|
|
|
2012-12-22 14:26:12 +00:00
|
|
|
let firstButton = iconChildren[0].child;
|
|
|
|
let firstIcon = firstButton._delegate.icon;
|
2011-09-20 15:59:25 +00:00
|
|
|
|
dash: Fix messed up icon height
When determining the biggest icon size that fits the available height,
we first subtract the additional space requirements of icons (spacing,
padding, running indicator etc.) and then divide the result by the
number of icons to get the maximum size available to each icon texture.
In the above, the additional space requirement of each icon is taken
from the first icon (as all icons are assumed to be the same), and
calculated as the difference between the icon button's preferred height
and the currently used icon size.
To make sure that the icon is actually using the dash's current icon
size (even while animating to a new icon size), we enforce its height
during the size request and restore its original height afterwards.
However after some recent changes, that step is causing troubles:
For some reason, the original height may be 0, and when we restore it,
we end up forcing a fixed non-height that bypasses the regular size
request machinery.
While it is unclear where exactly the zero height comes from (maybe
waiting for a valid resource scale?), it is clear that it's best
to avoid forcing a fixed height. So instead of making the icon
texture comply with the assumed icon size, adjust the calculations
to use its current height request.
https://gitlab.gnome.org/GNOME/gnome-shell/issues/1053
2019-04-09 01:03:54 +00:00
|
|
|
// Enforce valid spacings during the size request
|
2015-10-13 15:38:26 +00:00
|
|
|
firstIcon.icon.ensure_style();
|
2021-01-22 13:36:37 +00:00
|
|
|
const [, , iconWidth, iconHeight] = firstIcon.icon.get_preferred_size();
|
|
|
|
const [, , buttonWidth, buttonHeight] = firstButton.get_preferred_size();
|
2010-11-27 21:31:14 +00:00
|
|
|
|
2020-12-11 12:47:28 +00:00
|
|
|
// Subtract icon padding and box spacing from the available width
|
|
|
|
availWidth -= iconChildren.length * (buttonWidth - iconWidth) +
|
2011-09-20 15:59:25 +00:00
|
|
|
(iconChildren.length - 1) * spacing;
|
2010-11-27 21:31:14 +00:00
|
|
|
|
2021-01-22 13:36:37 +00:00
|
|
|
let availHeight = this._maxHeight;
|
2022-02-16 19:04:03 +00:00
|
|
|
availHeight -= this.margin_top + this.margin_bottom;
|
2021-01-22 13:36:37 +00:00
|
|
|
availHeight -= this._background.get_theme_node().get_vertical_padding();
|
|
|
|
availHeight -= themeNode.get_vertical_padding();
|
|
|
|
availHeight -= buttonHeight - iconHeight;
|
|
|
|
|
|
|
|
const maxIconSize = Math.min(availWidth / iconChildren.length, availHeight);
|
2011-09-19 21:47:16 +00:00
|
|
|
|
dash: Fix messed up icon height
When determining the biggest icon size that fits the available height,
we first subtract the additional space requirements of icons (spacing,
padding, running indicator etc.) and then divide the result by the
number of icons to get the maximum size available to each icon texture.
In the above, the additional space requirement of each icon is taken
from the first icon (as all icons are assumed to be the same), and
calculated as the difference between the icon button's preferred height
and the currently used icon size.
To make sure that the icon is actually using the dash's current icon
size (even while animating to a new icon size), we enforce its height
during the size request and restore its original height afterwards.
However after some recent changes, that step is causing troubles:
For some reason, the original height may be 0, and when we restore it,
we end up forcing a fixed non-height that bypasses the regular size
request machinery.
While it is unclear where exactly the zero height comes from (maybe
waiting for a valid resource scale?), it is clear that it's best
to avoid forcing a fixed height. So instead of making the icon
texture comply with the assumed icon size, adjust the calculations
to use its current height request.
https://gitlab.gnome.org/GNOME/gnome-shell/issues/1053
2019-04-09 01:03:54 +00:00
|
|
|
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
|
2017-10-31 00:38:18 +00:00
|
|
|
let iconSizes = baseIconSizes.map(s => s * scaleFactor);
|
2015-10-03 21:44:48 +00:00
|
|
|
|
2014-02-16 05:35:13 +00:00
|
|
|
let newIconSize = baseIconSizes[0];
|
2010-11-27 21:31:14 +00:00
|
|
|
for (let i = 0; i < iconSizes.length; i++) {
|
2021-01-22 13:36:37 +00:00
|
|
|
if (iconSizes[i] <= maxIconSize)
|
2014-02-16 05:35:13 +00:00
|
|
|
newIconSize = baseIconSizes[i];
|
2010-11-27 21:31:14 +00:00
|
|
|
}
|
|
|
|
|
2023-08-07 00:51:19 +00:00
|
|
|
if (newIconSize === this.iconSize)
|
2010-11-27 21:31:14 +00:00
|
|
|
return;
|
|
|
|
|
2011-02-12 00:17:10 +00:00
|
|
|
let oldIconSize = this.iconSize;
|
|
|
|
this.iconSize = newIconSize;
|
2011-08-28 13:35:13 +00:00
|
|
|
this.emit('icon-size-changed');
|
2010-11-27 21:31:14 +00:00
|
|
|
|
2011-01-21 11:06:13 +00:00
|
|
|
let scale = oldIconSize / newIconSize;
|
2010-11-27 21:31:14 +00:00
|
|
|
for (let i = 0; i < iconChildren.length; i++) {
|
2012-12-22 13:57:06 +00:00
|
|
|
let icon = iconChildren[i].child._delegate.icon;
|
2011-01-21 11:06:13 +00:00
|
|
|
|
|
|
|
// Set the new size immediately, to keep the icons' sizes
|
2011-02-12 00:17:10 +00:00
|
|
|
// in sync with this.iconSize
|
|
|
|
icon.setIconSize(this.iconSize);
|
2011-02-09 22:55:50 +00:00
|
|
|
|
|
|
|
// Don't animate the icon size change when the overview
|
2012-10-30 19:15:29 +00:00
|
|
|
// is transitioning, not visible or when initially filling
|
|
|
|
// the dash
|
|
|
|
if (!Main.overview.visible || Main.overview.animationInProgress ||
|
|
|
|
!this._shownInitially)
|
2011-02-09 22:55:50 +00:00
|
|
|
continue;
|
|
|
|
|
2011-01-21 11:06:13 +00:00
|
|
|
let [targetWidth, targetHeight] = icon.icon.get_size();
|
|
|
|
|
|
|
|
// Scale the icon's texture to the previous size and
|
|
|
|
// tween to the new size
|
2023-08-06 23:45:22 +00:00
|
|
|
icon.icon.set_size(
|
|
|
|
icon.icon.width * scale,
|
|
|
|
icon.icon.height * scale);
|
2011-01-21 11:06:13 +00:00
|
|
|
|
2018-07-20 19:46:19 +00:00
|
|
|
icon.icon.ease({
|
|
|
|
width: targetWidth,
|
|
|
|
height: targetHeight,
|
2019-10-10 00:14:28 +00:00
|
|
|
duration: DASH_ANIMATION_TIME,
|
2019-08-20 21:43:54 +00:00
|
|
|
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
2018-07-20 19:46:19 +00:00
|
|
|
});
|
2010-11-27 21:31:14 +00:00
|
|
|
}
|
2021-01-28 22:24:44 +00:00
|
|
|
|
|
|
|
if (this._separator) {
|
|
|
|
this._separator.ease({
|
|
|
|
height: this.iconSize,
|
|
|
|
duration: DASH_ANIMATION_TIME,
|
|
|
|
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
|
|
|
});
|
|
|
|
}
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2010-11-27 21:31:14 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_redisplay() {
|
2010-07-21 23:29:02 +00:00
|
|
|
let favorites = AppFavorites.getAppFavorites().getFavoriteMap();
|
|
|
|
|
apps: Ensure running apps override new .desktop file data
This patch fixes the "apps vanish from alt-TAB bug".
If a "package system" rips away and possibly replaces .desktop files
at some random time, we have historically used inotify to detect this
and reread state (in a racy way, but...). In GNOME 2, this was
generally not too problematic because the menu widget was totally
separate from the list of windows - and the data they operate on was
disjoint as well.
In GNOME 3 we unify these, and this creates architectural problems
because the windows are tied to the app.
What this patch tries to do is, when rereading the application state,
if we have a running application, we keep that app around instead of
making a new instance. This ensures we preserve any state such as the
set of open windows.
This requires moving the running state into ShellAppSystem. Adjust
callers as necessary, and while we're at it drop the unused "contexts"
stuff.
This is just a somewhat quick band-aid; a REAL fix would require us
having low-level control over application installation. As long as
we're on top of random broken tar+wget wrappers, it will be gross.
A slight future improvement to this patch would add an explicit
"merge" between the old and new data. I think probably we always keep
around the ShellApp corresponding to a given ID, but replace its
GMenuTreeEntry.
https://bugzilla.gnome.org/show_bug.cgi?id=657990
2011-09-03 14:32:06 +00:00
|
|
|
let running = this._appSystem.get_running();
|
2010-07-21 23:29:02 +00:00
|
|
|
|
2017-10-31 00:38:18 +00:00
|
|
|
let children = this._box.get_children().filter(actor => {
|
2019-01-29 19:36:54 +00:00
|
|
|
return actor.child &&
|
|
|
|
actor.child._delegate &&
|
|
|
|
actor.child._delegate.app;
|
|
|
|
});
|
2011-01-13 12:44:40 +00:00
|
|
|
// Apps currently in the dash
|
2017-10-31 00:38:18 +00:00
|
|
|
let oldApps = children.map(actor => actor.child._delegate.app);
|
2011-01-13 12:44:40 +00:00
|
|
|
// Apps supposed to be in the dash
|
|
|
|
let newApps = [];
|
|
|
|
|
|
|
|
for (let id in favorites)
|
|
|
|
newApps.push(favorites[id]);
|
2010-07-21 23:29:02 +00:00
|
|
|
|
|
|
|
for (let i = 0; i < running.length; i++) {
|
|
|
|
let app = running[i];
|
|
|
|
if (app.get_id() in favorites)
|
|
|
|
continue;
|
2011-01-13 12:44:40 +00:00
|
|
|
newApps.push(app);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Figure out the actual changes to the list of items; we iterate
|
|
|
|
// over both the list of items currently in the dash and the list
|
|
|
|
// of items expected there, and collect additions and removals.
|
|
|
|
// Moves are both an addition and a removal, where the order of
|
|
|
|
// the operations depends on whether we encounter the position
|
|
|
|
// where the item has been added first or the one from where it
|
|
|
|
// was removed.
|
|
|
|
// There is an assumption that only one item is moved at a given
|
|
|
|
// time; when moving several items at once, everything will still
|
|
|
|
// end up at the right position, but there might be additional
|
|
|
|
// additions/removals (e.g. it might remove all the launchers
|
|
|
|
// and add them back in the new order even if a smaller set of
|
|
|
|
// additions and removals is possible).
|
|
|
|
// If above assumptions turns out to be a problem, we might need
|
|
|
|
// to use a more sophisticated algorithm, e.g. Longest Common
|
|
|
|
// Subsequence as used by diff.
|
|
|
|
let addedItems = [];
|
|
|
|
let removedActors = [];
|
|
|
|
|
|
|
|
let newIndex = 0;
|
|
|
|
let oldIndex = 0;
|
|
|
|
while (newIndex < newApps.length || oldIndex < oldApps.length) {
|
2017-06-13 01:41:42 +00:00
|
|
|
let oldApp = oldApps.length > oldIndex ? oldApps[oldIndex] : null;
|
|
|
|
let newApp = newApps.length > newIndex ? newApps[newIndex] : null;
|
|
|
|
|
2011-01-13 12:44:40 +00:00
|
|
|
// No change at oldIndex/newIndex
|
2023-08-07 00:51:19 +00:00
|
|
|
if (oldApp === newApp) {
|
2011-01-13 12:44:40 +00:00
|
|
|
oldIndex++;
|
|
|
|
newIndex++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// App removed at oldIndex
|
2018-07-14 20:56:22 +00:00
|
|
|
if (oldApp && !newApps.includes(oldApp)) {
|
2011-01-13 12:44:40 +00:00
|
|
|
removedActors.push(children[oldIndex]);
|
|
|
|
oldIndex++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// App added at newIndex
|
2018-07-14 20:56:22 +00:00
|
|
|
if (newApp && !oldApps.includes(newApp)) {
|
2020-03-29 21:51:13 +00:00
|
|
|
addedItems.push({
|
|
|
|
app: newApp,
|
|
|
|
item: this._createAppItem(newApp),
|
|
|
|
pos: newIndex,
|
|
|
|
});
|
2011-01-13 12:44:40 +00:00
|
|
|
newIndex++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// App moved
|
2019-08-19 19:33:15 +00:00
|
|
|
let nextApp = newApps.length > newIndex + 1
|
|
|
|
? newApps[newIndex + 1] : null;
|
2023-08-07 00:51:19 +00:00
|
|
|
let insertHere = nextApp && nextApp === oldApp;
|
2017-10-31 00:38:18 +00:00
|
|
|
let alreadyRemoved = removedActors.reduce((result, actor) => {
|
2012-12-22 13:57:06 +00:00
|
|
|
let removedApp = actor.child._delegate.app;
|
2023-08-07 00:51:19 +00:00
|
|
|
return result || removedApp === newApp;
|
2011-01-13 12:44:40 +00:00
|
|
|
}, false);
|
|
|
|
|
|
|
|
if (insertHere || alreadyRemoved) {
|
2017-06-13 01:41:42 +00:00
|
|
|
let newItem = this._createAppItem(newApp);
|
2020-03-29 21:51:13 +00:00
|
|
|
addedItems.push({
|
|
|
|
app: newApp,
|
|
|
|
item: newItem,
|
|
|
|
pos: newIndex + removedActors.length,
|
|
|
|
});
|
2011-01-13 12:44:40 +00:00
|
|
|
newIndex++;
|
|
|
|
} else {
|
|
|
|
removedActors.push(children[oldIndex]);
|
|
|
|
oldIndex++;
|
|
|
|
}
|
2010-07-21 23:29:02 +00:00
|
|
|
}
|
|
|
|
|
2019-08-20 00:51:42 +00:00
|
|
|
for (let i = 0; i < addedItems.length; i++) {
|
2023-08-06 23:45:22 +00:00
|
|
|
this._box.insert_child_at_index(
|
|
|
|
addedItems[i].item,
|
|
|
|
addedItems[i].pos);
|
2019-08-20 00:51:42 +00:00
|
|
|
}
|
2011-01-13 12:44:40 +00:00
|
|
|
|
2011-09-19 21:47:16 +00:00
|
|
|
for (let i = 0; i < removedActors.length; i++) {
|
2012-12-22 13:57:06 +00:00
|
|
|
let item = removedActors[i];
|
2011-01-21 11:06:13 +00:00
|
|
|
|
2012-10-30 19:15:29 +00:00
|
|
|
// Don't animate item removal when the overview is transitioning
|
|
|
|
// or hidden
|
|
|
|
if (Main.overview.visible && !Main.overview.animationInProgress)
|
2011-09-19 21:47:16 +00:00
|
|
|
item.animateOutAndDestroy();
|
|
|
|
else
|
2012-04-08 19:35:41 +00:00
|
|
|
item.destroy();
|
2011-09-19 21:47:16 +00:00
|
|
|
}
|
2011-01-13 12:44:40 +00:00
|
|
|
|
2010-11-27 21:31:14 +00:00
|
|
|
this._adjustIconSize();
|
2011-01-21 11:06:13 +00:00
|
|
|
|
2011-02-02 15:44:07 +00:00
|
|
|
// Skip animations on first run when adding the initial set
|
|
|
|
// of items, to avoid all items zooming in at once
|
|
|
|
|
2012-12-22 14:26:12 +00:00
|
|
|
let animate = this._shownInitially && Main.overview.visible &&
|
|
|
|
!Main.overview.animationInProgress;
|
2011-02-06 16:46:12 +00:00
|
|
|
|
2012-12-22 14:26:12 +00:00
|
|
|
if (!this._shownInitially)
|
|
|
|
this._shownInitially = true;
|
|
|
|
|
2019-08-20 00:51:42 +00:00
|
|
|
for (let i = 0; i < addedItems.length; i++)
|
2012-12-22 14:26:12 +00:00
|
|
|
addedItems[i].item.show(animate);
|
2013-01-28 22:22:23 +00:00
|
|
|
|
2021-01-28 22:24:44 +00:00
|
|
|
// Update separator
|
|
|
|
const nFavorites = Object.keys(favorites).length;
|
2021-02-09 20:48:39 +00:00
|
|
|
const nIcons = children.length + addedItems.length - removedActors.length;
|
2021-01-29 18:03:07 +00:00
|
|
|
if (nFavorites > 0 && nFavorites < nIcons) {
|
2021-01-28 22:24:44 +00:00
|
|
|
if (!this._separator) {
|
|
|
|
this._separator = new St.Widget({
|
|
|
|
style_class: 'dash-separator',
|
|
|
|
y_align: Clutter.ActorAlign.CENTER,
|
|
|
|
height: this.iconSize,
|
|
|
|
});
|
|
|
|
this._box.add_child(this._separator);
|
|
|
|
}
|
2021-04-12 10:56:28 +00:00
|
|
|
let pos = nFavorites + this._animatingPlaceholdersCount;
|
2021-01-28 22:24:44 +00:00
|
|
|
if (this._dragPlaceholder)
|
|
|
|
pos++;
|
|
|
|
this._box.set_child_at_index(this._separator, pos);
|
|
|
|
} else if (this._separator) {
|
|
|
|
this._separator.destroy();
|
|
|
|
this._separator = null;
|
|
|
|
}
|
|
|
|
|
2013-01-28 22:22:23 +00:00
|
|
|
// Workaround for https://bugzilla.gnome.org/show_bug.cgi?id=692744
|
|
|
|
// Without it, StBoxLayout may use a stale size cache
|
|
|
|
this._box.queue_relayout();
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2010-07-21 23:29:02 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_clearDragPlaceholder() {
|
2010-11-08 01:51:02 +00:00
|
|
|
if (this._dragPlaceholder) {
|
2013-06-05 12:17:20 +00:00
|
|
|
this._animatingPlaceholdersCount++;
|
2017-10-31 00:38:18 +00:00
|
|
|
this._dragPlaceholder.connect('destroy', () => {
|
|
|
|
this._animatingPlaceholdersCount--;
|
|
|
|
});
|
2023-01-14 16:00:42 +00:00
|
|
|
this._dragPlaceholder.animateOutAndDestroy();
|
2010-11-08 01:51:02 +00:00
|
|
|
this._dragPlaceholder = null;
|
|
|
|
}
|
2013-05-31 15:47:48 +00:00
|
|
|
this._dragPlaceholderPos = -1;
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2010-11-08 01:51:02 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_clearEmptyDropTarget() {
|
2013-05-31 15:59:27 +00:00
|
|
|
if (this._emptyDropTarget) {
|
|
|
|
this._emptyDropTarget.animateOutAndDestroy();
|
|
|
|
this._emptyDropTarget = null;
|
|
|
|
}
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2013-05-31 15:59:27 +00:00
|
|
|
|
2020-12-11 12:47:28 +00:00
|
|
|
handleDragOver(source, actor, x, _y, _time) {
|
2023-08-19 16:31:24 +00:00
|
|
|
const app = Dash.getAppFromSource(source);
|
2010-07-21 23:29:02 +00:00
|
|
|
|
|
|
|
// Don't allow favoriting of transient apps
|
Kill off ShellAppInfo, move into ShellApp
This dramatically thins down and sanitizes the application code.
The ShellAppSystem changes in a number of ways:
* Preferences are special cased more explicitly; they aren't apps,
they're shortcuts for an app), and we don't have many of them, so
don't need e.g. the optimizations in ShellAppSystem for searching.
* get_app() changes to lookup_app() and returns null if an app isn't
found. The semantics where it tried to find the .desktop file
if we didn't know about it were just broken; I am pretty sure no
caller needs this, and if they do we'll fix them.
* ShellAppSystem maintains two indexes on apps (by desktop file id
and by GMenuTreeEntry), but is no longer in the business of
dealing with GMenuTree as far as hierarchy and categories go. That
is moved up into js/ui/appDisplay.js. Actually, it flattens both
apps and settings.
Also, ShellWindowTracker is now the sole reference-owner for
window-backed apps. We still do the weird "window:0x1234beef" id
for these apps, but a reference is not stored in ShellAppSystem.
The js/ui/appDisplay.js code is rewritten, and sucks a lot less.
Variable names are clearer:
_apps -> _appIcons
_filterApp -> _visibleApps
_filters -> _categoryBox
Similarly for function names. We no longer call (for every app) a
recursive lookup in GMenuTree to see if it's in a particular section
on every category switch; it's all cached.
NOTE - this intentionally reverts the incremental loading code from
commit 7813c5b93f6bcde8c4beae286e82bfc472b2b656. It's fast enough
here without that.
https://bugzilla.gnome.org/show_bug.cgi?id=648149
2011-04-21 17:35:01 +00:00
|
|
|
if (app == null || app.is_window_backed())
|
2010-07-21 23:29:02 +00:00
|
|
|
return DND.DragMotionResult.NO_DROP;
|
|
|
|
|
2015-03-20 19:56:52 +00:00
|
|
|
if (!global.settings.is_writable('favorite-apps'))
|
2014-12-11 15:22:19 +00:00
|
|
|
return DND.DragMotionResult.NO_DROP;
|
|
|
|
|
2011-01-06 13:19:44 +00:00
|
|
|
let favorites = AppFavorites.getAppFavorites().getFavorites();
|
|
|
|
let numFavorites = favorites.length;
|
|
|
|
|
|
|
|
let favPos = favorites.indexOf(app);
|
|
|
|
|
2011-01-21 11:06:13 +00:00
|
|
|
let children = this._box.get_children();
|
|
|
|
let numChildren = children.length;
|
2020-12-11 12:47:28 +00:00
|
|
|
let boxWidth = this._box.width;
|
2010-11-08 01:51:02 +00:00
|
|
|
|
|
|
|
// Keep the placeholder out of the index calculation; assuming that
|
|
|
|
// the remove target has the same size as "normal" items, we don't
|
|
|
|
// need to do the same adjustment there.
|
|
|
|
if (this._dragPlaceholder) {
|
2020-12-11 12:47:28 +00:00
|
|
|
boxWidth -= this._dragPlaceholder.width;
|
2010-11-08 01:51:02 +00:00
|
|
|
numChildren--;
|
|
|
|
}
|
|
|
|
|
2021-01-28 22:24:44 +00:00
|
|
|
// Same with the separator
|
|
|
|
if (this._separator) {
|
|
|
|
boxWidth -= this._separator.width;
|
|
|
|
numChildren--;
|
|
|
|
}
|
|
|
|
|
2013-05-31 15:59:27 +00:00
|
|
|
let pos;
|
2022-02-26 17:35:47 +00:00
|
|
|
if (this._emptyDropTarget)
|
|
|
|
pos = 0; // always insert at the start when dash is empty
|
|
|
|
else if (this.text_direction === Clutter.TextDirection.RTL)
|
|
|
|
pos = numChildren - Math.floor(x * numChildren / boxWidth);
|
2013-05-31 15:59:27 +00:00
|
|
|
else
|
2022-02-26 17:35:47 +00:00
|
|
|
pos = Math.floor(x * numChildren / boxWidth);
|
2012-01-26 14:35:31 +00:00
|
|
|
|
2020-05-13 16:28:53 +00:00
|
|
|
// Put the placeholder after the last favorite if we are not
|
|
|
|
// in the favorites zone
|
|
|
|
if (pos > numFavorites)
|
|
|
|
pos = numFavorites;
|
|
|
|
|
|
|
|
if (pos !== this._dragPlaceholderPos && this._animatingPlaceholdersCount === 0) {
|
2012-01-26 14:35:31 +00:00
|
|
|
this._dragPlaceholderPos = pos;
|
2011-01-06 13:19:44 +00:00
|
|
|
|
|
|
|
// Don't allow positioning before or after self
|
2023-08-07 00:51:19 +00:00
|
|
|
if (favPos !== -1 && (pos === favPos || pos === favPos + 1)) {
|
2013-06-05 12:17:20 +00:00
|
|
|
this._clearDragPlaceholder();
|
2011-01-06 13:19:44 +00:00
|
|
|
return DND.DragMotionResult.CONTINUE;
|
2011-01-21 11:06:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// If the placeholder already exists, we just move
|
|
|
|
// it, but if we are adding it, expand its size in
|
|
|
|
// an animation
|
|
|
|
let fadeIn;
|
|
|
|
if (this._dragPlaceholder) {
|
2012-12-22 13:57:06 +00:00
|
|
|
this._dragPlaceholder.destroy();
|
2011-01-21 11:06:13 +00:00
|
|
|
fadeIn = false;
|
|
|
|
} else {
|
|
|
|
fadeIn = true;
|
|
|
|
}
|
2011-01-06 13:19:44 +00:00
|
|
|
|
2011-01-20 15:23:43 +00:00
|
|
|
this._dragPlaceholder = new DragPlaceholderItem();
|
2019-08-19 17:55:49 +00:00
|
|
|
this._dragPlaceholder.child.set_width(this.iconSize);
|
|
|
|
this._dragPlaceholder.child.set_height(this.iconSize / 2);
|
2023-08-06 23:45:22 +00:00
|
|
|
this._box.insert_child_at_index(
|
|
|
|
this._dragPlaceholder,
|
|
|
|
this._dragPlaceholderPos);
|
2012-12-22 14:26:12 +00:00
|
|
|
this._dragPlaceholder.show(fadeIn);
|
2010-11-08 01:51:02 +00:00
|
|
|
}
|
|
|
|
|
2012-01-26 09:20:03 +00:00
|
|
|
if (!this._dragPlaceholder)
|
|
|
|
return DND.DragMotionResult.NO_DROP;
|
|
|
|
|
2023-08-07 00:51:19 +00:00
|
|
|
let srcIsFavorite = favPos !== -1;
|
2010-07-21 23:29:02 +00:00
|
|
|
|
|
|
|
if (srcIsFavorite)
|
2010-11-08 01:51:02 +00:00
|
|
|
return DND.DragMotionResult.MOVE_DROP;
|
2010-07-21 23:29:02 +00:00
|
|
|
|
|
|
|
return DND.DragMotionResult.COPY_DROP;
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2010-07-21 23:29:02 +00:00
|
|
|
|
|
|
|
// Draggable target interface
|
2019-01-31 14:08:10 +00:00
|
|
|
acceptDrop(source, _actor, _x, _y, _time) {
|
2023-08-19 16:31:24 +00:00
|
|
|
const app = Dash.getAppFromSource(source);
|
2010-07-21 23:29:02 +00:00
|
|
|
|
|
|
|
// Don't allow favoriting of transient apps
|
2019-08-20 00:51:42 +00:00
|
|
|
if (app == null || app.is_window_backed())
|
2010-07-21 23:29:02 +00:00
|
|
|
return false;
|
|
|
|
|
2015-03-20 19:56:52 +00:00
|
|
|
if (!global.settings.is_writable('favorite-apps'))
|
2014-12-11 15:22:19 +00:00
|
|
|
return false;
|
|
|
|
|
2010-07-21 23:29:02 +00:00
|
|
|
let id = app.get_id();
|
|
|
|
|
|
|
|
let favorites = AppFavorites.getAppFavorites().getFavoriteMap();
|
|
|
|
|
2019-08-19 19:38:51 +00:00
|
|
|
let srcIsFavorite = id in favorites;
|
2010-07-21 23:29:02 +00:00
|
|
|
|
2010-11-08 01:51:02 +00:00
|
|
|
let favPos = 0;
|
|
|
|
let children = this._box.get_children();
|
|
|
|
for (let i = 0; i < this._dragPlaceholderPos; i++) {
|
2011-01-21 11:06:13 +00:00
|
|
|
if (this._dragPlaceholder &&
|
2023-08-07 00:51:19 +00:00
|
|
|
children[i] === this._dragPlaceholder)
|
2011-01-21 11:06:13 +00:00
|
|
|
continue;
|
|
|
|
|
2012-12-22 13:57:06 +00:00
|
|
|
let childId = children[i].child._delegate.app.get_id();
|
2023-08-07 00:51:19 +00:00
|
|
|
if (childId === id)
|
2010-11-08 01:51:02 +00:00
|
|
|
continue;
|
|
|
|
if (childId in favorites)
|
|
|
|
favPos++;
|
|
|
|
}
|
|
|
|
|
2019-05-15 19:32:29 +00:00
|
|
|
// No drag placeholder means we don't want to favorite the app
|
2012-01-26 09:20:03 +00:00
|
|
|
// and we are dragging it to its original position
|
|
|
|
if (!this._dragPlaceholder)
|
|
|
|
return true;
|
|
|
|
|
2022-09-07 18:23:38 +00:00
|
|
|
const laters = global.compositor.get_laters();
|
|
|
|
laters.add(Meta.LaterType.BEFORE_REDRAW, () => {
|
2017-10-31 00:38:18 +00:00
|
|
|
let appFavorites = AppFavorites.getAppFavorites();
|
|
|
|
if (srcIsFavorite)
|
|
|
|
appFavorites.moveFavoriteToPos(id, favPos);
|
|
|
|
else
|
|
|
|
appFavorites.addFavoriteAtPos(id, favPos);
|
|
|
|
return false;
|
|
|
|
});
|
2010-07-21 23:29:02 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2021-01-22 13:36:37 +00:00
|
|
|
|
|
|
|
setMaxSize(maxWidth, maxHeight) {
|
|
|
|
if (this._maxWidth === maxWidth &&
|
|
|
|
this._maxHeight === maxHeight)
|
|
|
|
return;
|
|
|
|
|
|
|
|
this._maxWidth = maxWidth;
|
|
|
|
this._maxHeight = maxHeight;
|
|
|
|
this._queueRedisplay();
|
|
|
|
}
|
2019-07-16 09:24:13 +00:00
|
|
|
});
|