From d82b3cb765ad1b201d1d29f0e33d0a7d6dff888b Mon Sep 17 00:00:00 2001 From: matt1432 Date: Fri, 22 Sep 2023 01:34:36 -0400 Subject: [PATCH] feat(ags): implement overview into shell --- config/ags/config.js | 1 + config/ags/js/misc/popup.js | 16 +- config/ags/js/overview/main.js | 310 ++++++++++---------- config/ags/scss/widgets/overview.scss | 8 +- config/ags/scss/widgets/quick-settings.scss | 5 +- config/ags/style.css | 12 +- config/hypr/main.conf | 2 + 7 files changed, 184 insertions(+), 170 deletions(-) diff --git a/config/ags/config.js b/config/ags/config.js index 3dbae275..ba853d65 100644 --- a/config/ags/config.js +++ b/config/ags/config.js @@ -26,6 +26,7 @@ export default { 'notification-center': 500, 'calendar': 500, 'powermenu': 500, + 'overview': 500, }, windows: [ Powermenu, diff --git a/config/ags/js/misc/popup.js b/config/ags/js/misc/popup.js index 33a511d7..aeca01fe 100644 --- a/config/ags/js/misc/popup.js +++ b/config/ags/js/misc/popup.js @@ -4,14 +4,26 @@ const { closeWindow, openWindow } = ags.App; export const PopUp = ({name, child, transition = 'slide_down', ...params}) => Revealer({ ...params, // FIXME: popups don't work with revealers - setup: () => setTimeout(() => closeWindow(name), 100), + setup: () => { + setTimeout(() => { + closeWindow(name); + }, 100); + + // my eyes hurt + if (name == 'overview') { + setTimeout(() => { + openWindow(name); + closeWindow(name); + }, 700); + } + }, transition, transitionDuration: 500, connections: [[ags.App, (revealer, currentName, visible) => { if (currentName === name) { revealer.reveal_child = visible; - if (visible) + if (visible && name !== 'overview') openWindow('closer'); } }]], diff --git a/config/ags/js/overview/main.js b/config/ags/js/overview/main.js index 162f056a..7ca9405d 100644 --- a/config/ags/js/overview/main.js +++ b/config/ags/js/overview/main.js @@ -3,6 +3,7 @@ const { Hyprland, Applications } = ags.Service; const { Gtk } = imports.gi; import { EventBox } from '../misc/cursorbox.js'; +import { PopUp } from '../misc/popup.js'; const SCALE = 0.11; const MARGIN = 8; @@ -17,166 +18,159 @@ const DEFAULT_SPECIAL = { POS_Y: 170, }; +const WorkspaceRow = className => CenterBox({ + children: [ null, Box({ className: className }), null ], +}); + +const OverviewWidget = Box({ + className: 'overview', + vertical: true, + children: [ + WorkspaceRow('normal'), + WorkspaceRow('special'), + ], + connections: [ + [Hyprland, box => { + let childI = 0; + box._workspaces = [].concat(box.children[childI++].centerWidget.children, + box.children[childI].centerWidget.children) + .sort((a, b) => a._id - b._id); + box._updateWs(box); + box._updateApps(box); + }], + ], + properties: [ + ['workspaces'], + + ['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.splice(toRemove.indexOf(existingApp), 1); + + if (existingApp) { + fixed.move( + existingApp, + app.at[0] * SCALE, + app.at[1] * SCALE, + ); + existingApp.child.className = `window ${active}`; + existingApp.child.style = `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) - 5}px;`; + } + else { + fixed.put( + Revealer({ + transition: 'slide_right', + connections: [[Hyprland, rev => { + rev.revealChild = true; + }]], + properties: [ + ['address', app.address], + ['toDestroy', false] + ], + child: Icon({ + className: `window ${active}`, + style: `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) * 0.8}px;`, + 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); + }], + + ['updateWs', box => { + Hyprland.workspaces.forEach(ws => { + let currentWs = box._workspaces.find(ch => ch._id == ws.id); + if (!currentWs) { + var childI = 0; + if (ws.id < 0) { + childI = 1; + } + + 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: EventBox({ + tooltipText: `Workspace: ${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, + }), + }), + }), + }); + box.children[childI].centerWidget.add(currentWs); + } + }); + box.show_all(); + + // Make sure the order is correct + box._workspaces.forEach((workspace, i) => { + workspace.get_parent().reorder_child(workspace, i) + }); + }], + ], +}); + export const Overview = Window({ name: 'overview', layer: 'overlay', - popup: true, - anchor: 'top', - margin: [ 0, 0, 0, 0 ], - child: Box({ - className: 'overview', - vertical: true, - children: [ - CenterBox({ - children: [ - null, - Box({ - className: 'normal', - }), - null, - ], - }), - CenterBox({ - children: [ - null, - Box({ - className: 'special', - }), - null, - ], - }), - ], - connections: [ - [Hyprland, box => { - let childI = 0; - box._workspaces = [].concat(box.children[childI++].centerWidget.children, - box.children[childI].centerWidget.children) - .sort((a, b) => a._id - b._id); - - box._updateWs(box); - box._updateApps(box); - }], - ], - properties: [ - ['workspaces'], - - ['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.splice(toRemove.indexOf(existingApp), 1); - - if (existingApp) { - fixed.move( - existingApp, - app.at[0] * SCALE, - app.at[1] * SCALE, - ); - existingApp.child.className = `window ${active}`; - existingApp.child.style = `min-width: ${app.size[0] * SCALE - MARGIN}px; - min-height: ${app.size[1] * SCALE - MARGIN}px;`; - } - else { - fixed.put( - Revealer({ - transition: 'slide_right', - connections: [[Hyprland, rev => { - rev.revealChild = true; - }]], - properties: [ - ['address', app.address], - ['toDestroy', false] - ], - child: Icon({ - className: `window ${active}`, - style: `min-width: ${app.size[0] * SCALE - MARGIN}px; - min-height: ${app.size[1] * SCALE - MARGIN}px;`, - icon: app.class, - size: 40, - }), - }), - 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); - }], - - ['updateWs', box => { - Hyprland.workspaces.forEach(ws => { - let currentWs = box._workspaces.find(ch => ch._id == ws.id) - if (!currentWs) { - var childI = 0; - if (ws.id < 0) { - childI = 1; - } - - 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: EventBox({ - tooltipText: `Workspace: ${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, - }), - }), - }), - }); - box.children[childI].centerWidget.add(currentWs); - } - }); - box.show_all(); - - // Make sure the order is correct - box._workspaces.forEach((workspace, i) => { - workspace.get_parent().reorder_child(workspace, i) - }); - }], - ], + child: PopUp({ + name: 'overview', + transition: 'crossfade', + child: OverviewWidget, }), }); diff --git a/config/ags/scss/widgets/overview.scss b/config/ags/scss/widgets/overview.scss index 90f11f21..dc4038b6 100644 --- a/config/ags/scss/widgets/overview.scss +++ b/config/ags/scss/widgets/overview.scss @@ -1,10 +1,15 @@ .overview { + background-color: $bg; + border-radius: 30px; + border: 2px solid $contrastbg; + padding: 10px; min-height: 1px; min-width: 1px; .workspace { padding: 4px; border: 2px solid transparent; + transition: border-color 0.2s ease-in-out; border-radius: 10px; &.active { @@ -17,7 +22,8 @@ margin: 0 10px; transition: min-width 0.2s ease-in-out, min-height 0.2s ease-in-out, - border-color 0.2s ease-in-out; + border-color 0.2s ease-in-out, + font-size 0.2s ease-in-out; } .normal { diff --git a/config/ags/scss/widgets/quick-settings.scss b/config/ags/scss/widgets/quick-settings.scss index f65f7bf0..d11b98f4 100644 --- a/config/ags/scss/widgets/quick-settings.scss +++ b/config/ags/scss/widgets/quick-settings.scss @@ -3,10 +3,7 @@ min-width: 500px; padding: 0px 0px 0px 0px; background-color: $bg; - border-top-right-radius: 0px; - border-top-left-radius: 30px; - border-bottom-left-radius: 30px; - border-bottom-right-radius: 30px; + border-radius: 30px 0 30px 30px; border: 2px solid $contrastbg; } diff --git a/config/ags/style.css b/config/ags/style.css index 98f50920..a4b464bf 100644 --- a/config/ags/style.css +++ b/config/ags/style.css @@ -456,10 +456,7 @@ calendar:indeterminate { min-width: 500px; padding: 0px 0px 0px 0px; background-color: rgba(40, 42, 54, 0.8); - border-top-right-radius: 0px; - border-top-left-radius: 30px; - border-bottom-left-radius: 30px; - border-bottom-right-radius: 30px; + border-radius: 30px 0 30px 30px; border: 2px solid rgba(189, 147, 249, 0.8); } .title { @@ -666,18 +663,23 @@ calendar:indeterminate { transition: background-color 0.5s ease-in-out; } .overview { + background-color: rgba(40, 42, 54, 0.8); + border-radius: 30px; + border: 2px solid rgba(189, 147, 249, 0.8); + padding: 10px; min-height: 1px; min-width: 1px; } .overview .workspace { padding: 4px; border: 2px solid transparent; + transition: border-color 0.2s ease-in-out; border-radius: 10px; } .overview .workspace.active { border: 2px solid black; } .overview .workspace .window { border-radius: 10px; margin: 0 10px; - transition: min-width 0.2s ease-in-out, min-height 0.2s ease-in-out, border-color 0.2s ease-in-out; } + transition: min-width 0.2s ease-in-out, min-height 0.2s ease-in-out, border-color 0.2s ease-in-out, font-size 0.2s ease-in-out; } .overview .normal { margin-bottom: 5px; } .overview .normal .workspace .window { diff --git a/config/hypr/main.conf b/config/hypr/main.conf index 4b7f47aa..2f68facd 100644 --- a/config/hypr/main.conf +++ b/config/hypr/main.conf @@ -183,6 +183,8 @@ bind = $mainMod, right, movefocus, r bind = $mainMod, up, movefocus, u bind = $mainMod, down, movefocus, d +bind = ALT, Tab, exec, ags -t overview + # Switch workspaces with mainMod + [0-9] bind = $mainMod, 1, workspace, 1 bind = $mainMod, 2, workspace, 2