refactor(ags): separate overview in multiple files
This commit is contained in:
parent
db735af50b
commit
e6848e2184
6 changed files with 246 additions and 230 deletions
|
@ -5,7 +5,7 @@ import { NotificationCenter } from './js/notifications/center.js';
|
||||||
import { NotificationsPopupList } from './js/notifications/popup.js'
|
import { NotificationsPopupList } from './js/notifications/popup.js'
|
||||||
import { Calendar } from './js/date.js';
|
import { Calendar } from './js/date.js';
|
||||||
import { QuickSettings } from './js/quick-settings/main.js';
|
import { QuickSettings } from './js/quick-settings/main.js';
|
||||||
import { Overview } from './js/overview/main.js';
|
import Overview from './js/overview/main.js';
|
||||||
|
|
||||||
import { Closer, closeAll } from './js/misc/closer.js';
|
import { Closer, closeAll } from './js/misc/closer.js';
|
||||||
ags.App.closeAll = () => closeAll();
|
ags.App.closeAll = () => closeAll();
|
||||||
|
|
105
config/ags/js/overview/clients.js
Normal file
105
config/ags/js/overview/clients.js
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
const { Icon, Revealer } = ags.Widget;
|
||||||
|
const { closeWindow } = ags.App;
|
||||||
|
const { execAsync } = ags.Utils;
|
||||||
|
const { Hyprland } = ags.Service;
|
||||||
|
|
||||||
|
import { WindowButton } from './dragndrop.js';
|
||||||
|
import * as VARS from './variables.js';
|
||||||
|
|
||||||
|
Array.prototype.remove = function (el) { this.splice(this.indexOf(el), 1) };
|
||||||
|
const IconStyle = app => `min-width: ${app.size[0] * VARS.SCALE - VARS.MARGIN}px;
|
||||||
|
min-height: ${app.size[1] * VARS.SCALE - VARS.MARGIN}px;
|
||||||
|
font-size: ${Math.min(app.size[0] * VARS.SCALE - VARS.MARGIN,
|
||||||
|
app.size[1] * VARS.SCALE - VARS.MARGIN) * VARS.ICON_SCALE}px;`;
|
||||||
|
|
||||||
|
const Client = (client, active) => Revealer({
|
||||||
|
transition: 'crossfade',
|
||||||
|
setup: rev => {
|
||||||
|
rev.revealChild = true;
|
||||||
|
},
|
||||||
|
properties: [
|
||||||
|
['address', client.address],
|
||||||
|
['toDestroy', false]
|
||||||
|
],
|
||||||
|
child: WindowButton({
|
||||||
|
address: client.address,
|
||||||
|
onSecondaryClickRelease: () => {
|
||||||
|
execAsync(`hyprctl dispatch closewindow address:${client.address}`)
|
||||||
|
.catch(print)
|
||||||
|
},
|
||||||
|
onPrimaryClickRelease: () => {
|
||||||
|
if (client.class === 'thunderbird' || client.class === 'Spotify')
|
||||||
|
execAsync(['bash', '-c', `$AGS_PATH/launch-app.sh ${client.class}`])
|
||||||
|
.then(() => closeWindow('overview'))
|
||||||
|
.catch(print);
|
||||||
|
else
|
||||||
|
execAsync(`hyprctl dispatch focuswindow address:${client.address}`)
|
||||||
|
.then(() => closeWindow('overview'))
|
||||||
|
.catch(print);
|
||||||
|
},
|
||||||
|
child: Icon({
|
||||||
|
className: `window ${active}`,
|
||||||
|
style: IconStyle(client),
|
||||||
|
icon: client.class,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
export function updateClients(box) {
|
||||||
|
ags.Utils.execAsync('hyprctl clients -j')
|
||||||
|
.then(result => {
|
||||||
|
let clients = JSON.parse(result).filter(client => client.class)
|
||||||
|
|
||||||
|
box._workspaces.forEach(workspace => {
|
||||||
|
let fixed = workspace.child.child.children[0];
|
||||||
|
let toRemove = fixed.get_children();
|
||||||
|
|
||||||
|
clients.filter(client => client.workspace.id == workspace._id).forEach(client => {
|
||||||
|
let active = '';
|
||||||
|
if (client.address == Hyprland.active.client.address) {
|
||||||
|
active = 'active';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special workspaces that haven't been opened yet
|
||||||
|
// return a size of 0. We need to set them to default
|
||||||
|
// values to show the workspace properly
|
||||||
|
if (client.size[0] === 0) {
|
||||||
|
client.size[0] = VARS.DEFAULT_SPECIAL.SIZE_X;
|
||||||
|
client.size[1] = VARS.DEFAULT_SPECIAL.SIZE_Y;
|
||||||
|
client.at[0] = VARS.DEFAULT_SPECIAL.POS_X;
|
||||||
|
client.at[1] = VARS.DEFAULT_SPECIAL.POS_Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
let existingClient = fixed.get_children().find(ch => ch._address == client.address);
|
||||||
|
toRemove.remove(existingClient);
|
||||||
|
|
||||||
|
if (existingClient) {
|
||||||
|
fixed.move(
|
||||||
|
existingClient,
|
||||||
|
client.at[0] * VARS.SCALE,
|
||||||
|
client.at[1] * VARS.SCALE,
|
||||||
|
);
|
||||||
|
existingClient.child.child.className = `window ${active}`;
|
||||||
|
existingClient.child.child.style = IconStyle(client);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fixed.put(
|
||||||
|
Client(client, active),
|
||||||
|
client.at[0] * VARS.SCALE,
|
||||||
|
client.at[1] * VARS.SCALE,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
fixed.show_all();
|
||||||
|
toRemove.forEach(ch => {
|
||||||
|
if (ch._toDestroy) {
|
||||||
|
ch.destroy();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ch.revealChild = false;
|
||||||
|
ch._toDestroy = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}).catch(print);
|
||||||
|
};
|
|
@ -51,7 +51,7 @@ export const WindowButton = ({address, ...params} = {}) => Button({
|
||||||
button.connect('drag-end', () => {
|
button.connect('drag-end', () => {
|
||||||
button.get_parent().destroy();
|
button.get_parent().destroy();
|
||||||
let mainBox = getWindow('overview').child.child;
|
let mainBox = getWindow('overview').child.child;
|
||||||
mainBox._updateApps(mainBox);
|
mainBox._updateClients(mainBox);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,239 +1,50 @@
|
||||||
const { Window, Box, CenterBox, Icon, Revealer } = ags.Widget;
|
const { Window, Box } = ags.Widget;
|
||||||
const { closeWindow } = ags.App;
|
|
||||||
const { execAsync } = ags.Utils;
|
|
||||||
const { Hyprland } = ags.Service;
|
const { Hyprland } = ags.Service;
|
||||||
const { Gtk } = imports.gi;
|
|
||||||
|
|
||||||
import { PopUp } from '../misc/popup.js';
|
import { PopUp } from '../misc/popup.js';
|
||||||
import { WorkspaceDrop, WindowButton } from './dragndrop.js';
|
import { WorkspaceRow, getWorkspaces, updateWorkspaces } from './workspaces.js';
|
||||||
|
import { updateClients } from './clients.js';
|
||||||
|
|
||||||
const WORKSPACE_PER_ROW = 6;
|
export default Window({
|
||||||
const SCALE = 0.11;
|
|
||||||
const ICON_SCALE = 0.8;
|
|
||||||
const MARGIN = 8;
|
|
||||||
const SCREEN = {
|
|
||||||
X: 1920,
|
|
||||||
Y: 1200,
|
|
||||||
}
|
|
||||||
const DEFAULT_SPECIAL = {
|
|
||||||
SIZE_X: 1524,
|
|
||||||
SIZE_Y: 908,
|
|
||||||
POS_X: 197,
|
|
||||||
POS_Y: 170,
|
|
||||||
};
|
|
||||||
const IconStyle = app => `min-width: ${app.size[0] * SCALE - MARGIN}px;
|
|
||||||
min-height: ${app.size[1] * SCALE - MARGIN}px;
|
|
||||||
font-size: ${Math.min(app.size[0] * SCALE - MARGIN,
|
|
||||||
app.size[1] * SCALE - MARGIN) * ICON_SCALE}px;`;
|
|
||||||
Array.prototype.remove = function (el) { this.splice(this.indexOf(el), 1) };
|
|
||||||
|
|
||||||
const WorkspaceRow = (className, i) => Revealer({
|
|
||||||
transition: 'slide_down',
|
|
||||||
connections: [[Hyprland, rev => {
|
|
||||||
rev.revealChild = Hyprland.workspaces.some(ws => ws.id > i * WORKSPACE_PER_ROW &&
|
|
||||||
(ws.windows > 0 ||
|
|
||||||
ws.id === Hyprland.active.workspace.id));
|
|
||||||
}]],
|
|
||||||
child: CenterBox({
|
|
||||||
children: [null, Box({
|
|
||||||
className: className,
|
|
||||||
}), null],
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
const OverviewWidget = Box({
|
|
||||||
className: 'overview',
|
|
||||||
vertical: true,
|
|
||||||
children: [
|
|
||||||
Box({
|
|
||||||
vertical: true,
|
|
||||||
children: [
|
|
||||||
WorkspaceRow('normal', 0),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
Box({
|
|
||||||
vertical: true,
|
|
||||||
children: [
|
|
||||||
WorkspaceRow('special', 0),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
connections: [
|
|
||||||
[Hyprland, box => {
|
|
||||||
box._getWorkspaces(box);
|
|
||||||
box._updateWs(box);
|
|
||||||
box._updateApps(box);
|
|
||||||
}],
|
|
||||||
],
|
|
||||||
properties: [
|
|
||||||
['workspaces'],
|
|
||||||
|
|
||||||
['getWorkspaces', box => {
|
|
||||||
let children = [];
|
|
||||||
box.children.forEach(type => {
|
|
||||||
type.children.forEach(row => {
|
|
||||||
row.child.centerWidget.children.forEach(ch => {
|
|
||||||
children.push(ch);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
box._workspaces = children.sort((a, b) => a._id - b._id);
|
|
||||||
}],
|
|
||||||
|
|
||||||
['updateWs', box => {
|
|
||||||
Hyprland.workspaces.forEach(ws => {
|
|
||||||
let currentWs = box._workspaces.find(ch => ch._id == ws.id);
|
|
||||||
if (!currentWs) {
|
|
||||||
var type = 0;
|
|
||||||
var rowNo = 0;
|
|
||||||
|
|
||||||
if (ws.id < 0) {
|
|
||||||
// This means it's a special workspace
|
|
||||||
type = 1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
rowNo = Math.floor((ws.id - 1) / WORKSPACE_PER_ROW);
|
|
||||||
if (rowNo >= box.children[type].children.length) {
|
|
||||||
for (let i = box.children[type].children.length; i <= rowNo; ++i) {
|
|
||||||
box.children[type].add(WorkspaceRow('normal', i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var row = box.children[type].children[rowNo].child.centerWidget;
|
|
||||||
|
|
||||||
currentWs = Revealer({
|
|
||||||
transition: 'slide_right',
|
|
||||||
properties: [
|
|
||||||
['id', ws.id],
|
|
||||||
],
|
|
||||||
connections: [[Hyprland, box => {
|
|
||||||
let active = Hyprland.active.workspace.id === box._id;
|
|
||||||
box.child.child.toggleClassName('active', active);
|
|
||||||
box.revealChild = Hyprland.getWorkspace(box._id)?.windows > 0 || active;
|
|
||||||
}]],
|
|
||||||
child: WorkspaceDrop({
|
|
||||||
id: ws.id,
|
|
||||||
child: Box({
|
|
||||||
className: 'workspace',
|
|
||||||
style: `min-width: ${SCREEN.X * SCALE}px;
|
|
||||||
min-height: ${SCREEN.Y * SCALE}px;`,
|
|
||||||
child: ags.Widget({
|
|
||||||
type: Gtk.Fixed,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
row.add(currentWs);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
box.show_all();
|
|
||||||
|
|
||||||
// Make sure the order is correct
|
|
||||||
box._workspaces.forEach((workspace, i) => {
|
|
||||||
workspace.get_parent().reorder_child(workspace, i)
|
|
||||||
});
|
|
||||||
}],
|
|
||||||
|
|
||||||
['updateApps', box => {
|
|
||||||
ags.Utils.execAsync('hyprctl clients -j')
|
|
||||||
.then(result => {
|
|
||||||
let clients = JSON.parse(result).filter(client => client.class)
|
|
||||||
|
|
||||||
box._workspaces.forEach(workspace => {
|
|
||||||
let fixed = workspace.child.child.children[0];
|
|
||||||
let toRemove = fixed.get_children();
|
|
||||||
|
|
||||||
clients.filter(app => app.workspace.id == workspace._id).forEach(app => {
|
|
||||||
let active = '';
|
|
||||||
if (app.address == Hyprland.active.client.address) {
|
|
||||||
active = 'active';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Special workspaces that haven't been opened yet
|
|
||||||
// return a size of 0. We need to set them to default
|
|
||||||
// values to show the workspace properly
|
|
||||||
if (app.size[0] === 0) {
|
|
||||||
app.size[0] = DEFAULT_SPECIAL.SIZE_X;
|
|
||||||
app.size[1] = DEFAULT_SPECIAL.SIZE_Y;
|
|
||||||
app.at[0] = DEFAULT_SPECIAL.POS_X;
|
|
||||||
app.at[1] = DEFAULT_SPECIAL.POS_Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
let existingApp = fixed.get_children().find(ch => ch._address == app.address);
|
|
||||||
toRemove.remove(existingApp);
|
|
||||||
|
|
||||||
if (existingApp) {
|
|
||||||
fixed.move(
|
|
||||||
existingApp,
|
|
||||||
app.at[0] * SCALE,
|
|
||||||
app.at[1] * SCALE,
|
|
||||||
);
|
|
||||||
existingApp.child.child.className = `window ${active}`;
|
|
||||||
existingApp.child.child.style = IconStyle(app);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fixed.put(
|
|
||||||
Revealer({
|
|
||||||
transition: 'crossfade',
|
|
||||||
setup: rev => {
|
|
||||||
rev.revealChild = true;
|
|
||||||
},
|
|
||||||
properties: [
|
|
||||||
['address', app.address],
|
|
||||||
['toDestroy', false]
|
|
||||||
],
|
|
||||||
child: WindowButton({
|
|
||||||
address: app.address,
|
|
||||||
onSecondaryClickRelease: () => {
|
|
||||||
execAsync(`hyprctl dispatch closewindow address:${address}`)
|
|
||||||
.catch(print)
|
|
||||||
},
|
|
||||||
onPrimaryClickRelease: () => {
|
|
||||||
if (app.class === 'thunderbird' || app.class === 'Spotify')
|
|
||||||
execAsync(['bash', '-c', `$AGS_PATH/launch-app.sh ${app.class}`])
|
|
||||||
.then(() => closeWindow('overview'))
|
|
||||||
.catch(print);
|
|
||||||
else
|
|
||||||
execAsync(`hyprctl dispatch focuswindow address:${app.address}`)
|
|
||||||
.then(() => closeWindow('overview'))
|
|
||||||
.catch(print);
|
|
||||||
},
|
|
||||||
child: Icon({
|
|
||||||
className: `window ${active}`,
|
|
||||||
style: IconStyle(app),
|
|
||||||
icon: app.class,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
app.at[0] * SCALE,
|
|
||||||
app.at[1] * SCALE,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
fixed.show_all();
|
|
||||||
toRemove.forEach(ch => {
|
|
||||||
if (ch._toDestroy) {
|
|
||||||
ch.destroy();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ch.revealChild = false;
|
|
||||||
ch._toDestroy = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}).catch(print);
|
|
||||||
}],
|
|
||||||
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
export const Overview = Window({
|
|
||||||
name: 'overview',
|
name: 'overview',
|
||||||
layer: 'overlay',
|
layer: 'overlay',
|
||||||
|
|
||||||
child: PopUp({
|
child: PopUp({
|
||||||
name: 'overview',
|
name: 'overview',
|
||||||
transition: 'crossfade',
|
transition: 'crossfade',
|
||||||
child: OverviewWidget,
|
|
||||||
|
child: Box({
|
||||||
|
className: 'overview',
|
||||||
|
vertical: true,
|
||||||
|
children: [
|
||||||
|
Box({
|
||||||
|
vertical: true,
|
||||||
|
children: [
|
||||||
|
WorkspaceRow('normal', 0),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
Box({
|
||||||
|
vertical: true,
|
||||||
|
children: [
|
||||||
|
WorkspaceRow('special', 0),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
connections: [
|
||||||
|
[Hyprland, box => {
|
||||||
|
box._getWorkspaces(box);
|
||||||
|
box._updateWorkspaces(box);
|
||||||
|
box._updateClients(box);
|
||||||
|
}],
|
||||||
|
],
|
||||||
|
properties: [
|
||||||
|
['workspaces'],
|
||||||
|
|
||||||
|
['getWorkspaces', getWorkspaces],
|
||||||
|
['updateWorkspaces', updateWorkspaces],
|
||||||
|
['updateClients', updateClients],
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
14
config/ags/js/overview/variables.js
Normal file
14
config/ags/js/overview/variables.js
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
export const SCALE = 0.11;
|
||||||
|
export const ICON_SCALE = 0.8;
|
||||||
|
export const MARGIN = 8;
|
||||||
|
export const DEFAULT_SPECIAL = {
|
||||||
|
SIZE_X: 1524,
|
||||||
|
SIZE_Y: 908,
|
||||||
|
POS_X: 197,
|
||||||
|
POS_Y: 170,
|
||||||
|
};
|
||||||
|
export const WORKSPACE_PER_ROW = 6;
|
||||||
|
export const SCREEN = {
|
||||||
|
X: 1920,
|
||||||
|
Y: 1200,
|
||||||
|
};
|
86
config/ags/js/overview/workspaces.js
Normal file
86
config/ags/js/overview/workspaces.js
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
const { Revealer, CenterBox, Box } = ags.Widget;
|
||||||
|
const { Hyprland } = ags.Service;
|
||||||
|
const { Gtk } = imports.gi;
|
||||||
|
|
||||||
|
import { WorkspaceDrop } from './dragndrop.js';
|
||||||
|
import * as VARS from './variables.js';
|
||||||
|
|
||||||
|
export function getWorkspaces(box) {
|
||||||
|
let children = [];
|
||||||
|
box.children.forEach(type => {
|
||||||
|
type.children.forEach(row => {
|
||||||
|
row.child.centerWidget.children.forEach(ch => {
|
||||||
|
children.push(ch);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
box._workspaces = children.sort((a, b) => a._id - b._id);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const WorkspaceRow = (className, i) => Revealer({
|
||||||
|
transition: 'slide_down',
|
||||||
|
connections: [[Hyprland, rev => {
|
||||||
|
rev.revealChild = Hyprland.workspaces.some(ws => ws.id > i * VARS.WORKSPACE_PER_ROW &&
|
||||||
|
(ws.windows > 0 ||
|
||||||
|
ws.id === Hyprland.active.workspace.id));
|
||||||
|
}]],
|
||||||
|
child: CenterBox({
|
||||||
|
children: [null, Box({
|
||||||
|
className: className,
|
||||||
|
}), null],
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const Workspace = id => Revealer({
|
||||||
|
transition: 'slide_right',
|
||||||
|
properties: [
|
||||||
|
['id', id],
|
||||||
|
],
|
||||||
|
connections: [[Hyprland, box => {
|
||||||
|
let active = Hyprland.active.workspace.id === box._id;
|
||||||
|
box.child.child.toggleClassName('active', active);
|
||||||
|
box.revealChild = Hyprland.getWorkspace(box._id)?.windows > 0 || active;
|
||||||
|
}]],
|
||||||
|
child: WorkspaceDrop({
|
||||||
|
id: id,
|
||||||
|
child: Box({
|
||||||
|
className: 'workspace',
|
||||||
|
style: `min-width: ${VARS.SCREEN.X * VARS.SCALE}px;
|
||||||
|
min-height: ${VARS.SCREEN.Y * VARS.SCALE}px;`,
|
||||||
|
child: ags.Widget({
|
||||||
|
type: Gtk.Fixed,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
export function updateWorkspaces(box) {
|
||||||
|
Hyprland.workspaces.forEach(ws => {
|
||||||
|
let currentWs = box._workspaces.find(ch => ch._id == ws.id);
|
||||||
|
if (!currentWs) {
|
||||||
|
var type = 0;
|
||||||
|
var rowNo = 0;
|
||||||
|
|
||||||
|
if (ws.id < 0) {
|
||||||
|
// This means it's a special workspace
|
||||||
|
type = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rowNo = Math.floor((ws.id - 1) / VARS.WORKSPACE_PER_ROW);
|
||||||
|
if (rowNo >= box.children[type].children.length) {
|
||||||
|
for (let i = box.children[type].children.length; i <= rowNo; ++i) {
|
||||||
|
box.children[type].add(WorkspaceRow('normal', i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var row = box.children[type].children[rowNo].child.centerWidget;
|
||||||
|
row.add(Workspace(ws.id));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
box.show_all();
|
||||||
|
|
||||||
|
// Make sure the order is correct
|
||||||
|
box._workspaces.forEach((workspace, i) => {
|
||||||
|
workspace.get_parent().reorder_child(workspace, i)
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in a new issue