From e6848e2184ee7b86696c692c9c34e12c96388d33 Mon Sep 17 00:00:00 2001 From: matt1432 Date: Sat, 23 Sep 2023 18:41:05 -0400 Subject: [PATCH] refactor(ags): separate overview in multiple files --- config/ags/config.js | 2 +- config/ags/js/overview/clients.js | 105 +++++++++++ config/ags/js/overview/dragndrop.js | 2 +- config/ags/js/overview/main.js | 267 ++++----------------------- config/ags/js/overview/variables.js | 14 ++ config/ags/js/overview/workspaces.js | 86 +++++++++ 6 files changed, 246 insertions(+), 230 deletions(-) create mode 100644 config/ags/js/overview/clients.js create mode 100644 config/ags/js/overview/variables.js create mode 100644 config/ags/js/overview/workspaces.js diff --git a/config/ags/config.js b/config/ags/config.js index ba853d65..7b17ac8e 100644 --- a/config/ags/config.js +++ b/config/ags/config.js @@ -5,7 +5,7 @@ import { NotificationCenter } from './js/notifications/center.js'; import { NotificationsPopupList } from './js/notifications/popup.js' import { Calendar } from './js/date.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'; ags.App.closeAll = () => closeAll(); diff --git a/config/ags/js/overview/clients.js b/config/ags/js/overview/clients.js new file mode 100644 index 00000000..cc74bc22 --- /dev/null +++ b/config/ags/js/overview/clients.js @@ -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); +}; diff --git a/config/ags/js/overview/dragndrop.js b/config/ags/js/overview/dragndrop.js index 0d566365..15b8843a 100644 --- a/config/ags/js/overview/dragndrop.js +++ b/config/ags/js/overview/dragndrop.js @@ -51,7 +51,7 @@ export const WindowButton = ({address, ...params} = {}) => Button({ button.connect('drag-end', () => { button.get_parent().destroy(); let mainBox = getWindow('overview').child.child; - mainBox._updateApps(mainBox); + mainBox._updateClients(mainBox); }); }, }); diff --git a/config/ags/js/overview/main.js b/config/ags/js/overview/main.js index 7576d7f5..882f8222 100644 --- a/config/ags/js/overview/main.js +++ b/config/ags/js/overview/main.js @@ -1,239 +1,50 @@ -const { Window, Box, CenterBox, Icon, Revealer } = ags.Widget; -const { closeWindow } = ags.App; -const { execAsync } = ags.Utils; +const { Window, Box } = ags.Widget; const { Hyprland } = ags.Service; -const { Gtk } = imports.gi; 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; -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({ +export default Window({ name: 'overview', layer: 'overlay', + child: PopUp({ name: 'overview', 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], + ], + }), + }), }); diff --git a/config/ags/js/overview/variables.js b/config/ags/js/overview/variables.js new file mode 100644 index 00000000..5bc871a8 --- /dev/null +++ b/config/ags/js/overview/variables.js @@ -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, +}; diff --git a/config/ags/js/overview/workspaces.js b/config/ags/js/overview/workspaces.js new file mode 100644 index 00000000..67cbd4d3 --- /dev/null +++ b/config/ags/js/overview/workspaces.js @@ -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) + }); +}