diff --git a/.config/ags/config.js b/.config/ags/config.js index c50e60b1f..3959ae475 100644 --- a/.config/ags/config.js +++ b/.config/ags/config.js @@ -1,13 +1,14 @@ "use strict"; // Import +import Gdk from 'gi://Gdk'; import App from 'resource:///com/github/Aylur/ags/app.js' import * as Utils from 'resource:///com/github/Aylur/ags/utils.js' // Widgets -import Bar from './widgets/bar/main.js'; +import { Bar, BarCornerTopleft, BarCornerTopright } from './widgets/bar/main.js'; import Cheatsheet from './widgets/cheatsheet/main.js'; import DesktopBackground from './widgets/desktopbackground/main.js'; // import Dock from './widgets/dock/main.js'; -import { CornerTopleft, CornerTopright, CornerBottomleft, CornerBottomright } from './widgets/screencorners/main.js'; +import Corner from './widgets/screencorners/main.js'; import Indicator from './widgets/indicators/main.js'; import Osk from './widgets/onscreenkeyboard/main.js'; import Overview from './widgets/overview/main.js'; @@ -15,7 +16,11 @@ import Session from './widgets/session/main.js'; import SideLeft from './widgets/sideleft/main.js'; import SideRight from './widgets/sideright/main.js'; -const CLOSE_ANIM_TIME = 210; // Longer than actual anim time (see styles) to make sure widgets animate fully +const range = (length, start = 1) => Array.from({ length }, (_, i) => i + start); +function forMonitors(widget) { + const n = Gdk.Display.get_default()?.get_n_monitors() || 1; + return range(n, 0).map(widget).flat(1); +} // SCSS compilation Utils.exec(`bash -c 'echo "" > ${App.configDir}/scss/_musicwal.scss'`); // reset music styles @@ -28,7 +33,25 @@ function applyStyle() { } applyStyle(); -// Config object +const Windows = () => [ + DesktopBackground(), + // Dock(), + Overview(), + forMonitors(Indicator), + Cheatsheet(), + SideLeft(), + SideRight(), + Osk(), + Session(), + Bar(), + BarCornerTopleft(), + BarCornerTopright(), + forMonitors((id) => Corner(id, 'top left')), + forMonitors((id) => Corner(id, 'top right')), + forMonitors((id) => Corner(id, 'bottom left')), + forMonitors((id) => Corner(id, 'bottom right')), +]; +const CLOSE_ANIM_TIME = 210; // Longer than actual anim time to make sure widgets animate fully export default { css: `${App.configDir}/style.css`, stackTraceOnError: true, @@ -37,20 +60,5 @@ export default { 'sideleft': CLOSE_ANIM_TIME, 'osk': CLOSE_ANIM_TIME, }, - windows: [ - CornerTopleft(), - CornerTopright(), - CornerBottomleft(), - CornerBottomright(), - DesktopBackground(), // If you're going to uncomment these, - // Dock(), // Buggy // uncomment the import statement too. - Overview(), - Indicator(), - Cheatsheet(), - SideLeft(), - SideRight(), - Osk(), // On-screen keyboard - Session(), // Power menu, if that's what you like to call it - Bar(), - ], + windows: Windows().flat(1), }; diff --git a/.config/ags/imports.js b/.config/ags/imports.js index 61dec2bf0..e5e1ab889 100644 --- a/.config/ags/imports.js +++ b/.config/ags/imports.js @@ -3,20 +3,19 @@ const require = async file => (await import(resource(file))).default; const service = async file => (await require(`service/${file}`)); export const App = await require('app'); -export const Widget = await require('widget'); -export const Service = await require('service'); -export const Variable = await require('variable'); +// export const Widget = await require('widget'); +// export const Service = await require('service'); +// export const Variable = await require('variable'); export const Utils = await import(resource('utils')); - -export const Applications = await service('applications'); -export const Audio = await service('audio'); -export const Battery = await service('battery'); -export const Bluetooth = await service('bluetooth'); +// export const Applications = await service('applications'); +// export const Audio = await service('audio'); +// export const Battery = await service('battery'); +// export const Bluetooth = await service('bluetooth'); // export const Hyprland = await service('hyprland'); export const Mpris = await service('mpris'); export const Network = await service('network'); export const Notifications = await service('notifications'); -export const SystemTray = await service('systemtray'); +// export const SystemTray = await service('systemtray'); globalThis['App'] = App; ////////////////////////////// // globalThis['Widget'] = Widget; diff --git a/.config/ags/lib/advancedwidgets.js b/.config/ags/lib/advancedwidgets.js index 096c55fde..e8dc378d7 100644 --- a/.config/ags/lib/advancedwidgets.js +++ b/.config/ags/lib/advancedwidgets.js @@ -40,7 +40,6 @@ export const MarginRevealer = ({ child.css = `margin-top: -${child.get_allocated_height()}px;`; }, 'toggle': () => { - console.log('toggle'); if (widget.attribute.revealChild) widget.attribute.hide(); else widget.attribute.show(); }, diff --git a/.config/ags/lib/roundedcorner.js b/.config/ags/lib/roundedcorner.js index 90c1cf07b..fd48d93e7 100644 --- a/.config/ags/lib/roundedcorner.js +++ b/.config/ags/lib/roundedcorner.js @@ -1,6 +1,10 @@ import Widget from 'resource:///com/github/Aylur/ags/widget.js'; const { Gtk } = imports.gi; const Lang = imports.lang; +import Cairo from 'gi://cairo?version=1.0'; + +export const dummyRegion = new Cairo.Region(); +export const enableClickthrough = (self) => self.input_shape_combine_region(dummyRegion); export const RoundedCorner = (place, props) => Widget.DrawingArea({ ...props, diff --git a/.config/ags/scss/_bar.scss b/.config/ags/scss/_bar.scss index 4f644f9ec..41cd21d22 100644 --- a/.config/ags/scss/_bar.scss +++ b/.config/ags/scss/_bar.scss @@ -331,6 +331,11 @@ $bar_subgroup_bg: $surfaceVariant; background-color: $onSurfaceVariant; } +.bar-corner-spacing { + min-width: $rounding_large; + min-height: $rounding_large; +} + .corner { background-color: $t_background; @include large-rounding; diff --git a/.config/ags/style.css b/.config/ags/style.css index 2fbb2ffd2..54d8845bc 100644 --- a/.config/ags/style.css +++ b/.config/ags/style.css @@ -823,6 +823,10 @@ tooltip { min-height: 0.409rem; background-color: #bfc8ca; } +.bar-corner-spacing { + min-width: 1.705rem; + min-height: 1.705rem; } + .corner { background-color: #0b0f10; border-radius: 1.705rem; @@ -2276,6 +2280,20 @@ tooltip { .notif-action-critical:active { background-color: #566e73; } +@keyframes flyin-top { + from { + margin-top: -2.795rem; } + to { + margin-top: 0rem; } } + +@keyframes flyin-bottom { + from { + margin-top: 4.841rem; + margin-bottom: -4.841rem; } + to { + margin-bottom: 0rem; + margin-top: 0rem; } } + .osd-music { transition: 300ms cubic-bezier(0.1, 1, 0, 1); box-shadow: 0px 2px 3px rgba(0, 0, 0, 0.45); diff --git a/.config/ags/widgets/bar/main.js b/.config/ags/widgets/bar/main.js index 025d1d4a8..11879add1 100644 --- a/.config/ags/widgets/bar/main.js +++ b/.config/ags/widgets/bar/main.js @@ -1,10 +1,11 @@ const { Gtk } = imports.gi; import Widget from 'resource:///com/github/Aylur/ags/widget.js'; -import { ModuleLeftSpace } from "./leftspace.js"; -import { ModuleRightSpace } from "./rightspace.js"; +import ModuleSpaceLeft from "./spaceleft.js"; +import ModuleSpaceRight from "./spaceright.js"; import { ModuleMusic } from "./music.js"; import { ModuleSystem } from "./system.js"; +import { RoundedCorner, dummyRegion, enableClickthrough } from "../../lib/roundedcorner.js"; const OptionalWorkspaces = async () => { try { return (await import('./workspaces_hyprland.js')).default(); @@ -13,42 +14,64 @@ const OptionalWorkspaces = async () => { return null; } }; +const optionalWorkspacesInstance = await OptionalWorkspaces(); -const left = Widget.Box({ - className: 'bar-sidemodule', - children: [ ModuleMusic()], -}); +export const Bar = (monitor = 0) => { + const left = Widget.Box({ + className: 'bar-sidemodule', + children: [ModuleMusic()], + }); -const center = Widget.Box({ - children: [await OptionalWorkspaces()], -}); + const center = Widget.Box({ + children: [optionalWorkspacesInstance], + }); -const right = Widget.Box({ - className: 'bar-sidemodule', - children: [ModuleSystem()], -}); - -export default () => Widget.Window({ - name: 'bar', - anchor: ['top', 'left', 'right'], - exclusivity: 'exclusive', - visible: true, - child: Widget.CenterBox({ - className: 'bar-bg', - startWidget: ModuleLeftSpace(), - centerWidget: Widget.Box({ - className: 'spacing-h-4', - children: [ - left, - center, - right, - ] + const right = Widget.Box({ + className: 'bar-sidemodule', + children: [ModuleSystem()], + }); + return Widget.Window({ + monitor, + name: `bar${monitor}`, + anchor: ['top', 'left', 'right'], + exclusivity: 'exclusive', + visible: true, + child: Widget.CenterBox({ + className: 'bar-bg', + startWidget: ModuleSpaceLeft(), + endWidget: ModuleSpaceRight(), + centerWidget: Widget.Box({ + className: 'spacing-h-4', + children: [ + left, + center, + right, + ] + }), + setup: (self) => { + const styleContext = self.get_style_context(); + const minHeight = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL); + // execAsync(['bash', '-c', `hyprctl keyword monitor ,addreserved,${minHeight},0,0,0`]).catch(print); + } }), - endWidget: ModuleRightSpace(), - setup: (self) => { - const styleContext = self.get_style_context(); - const minHeight = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL); - // execAsync(['bash', '-c', `hyprctl keyword monitor ,addreserved,${minHeight},0,0,0`]).catch(print); - } - }), + }); +} + +export const BarCornerTopleft = (id = '') => Widget.Window({ + name: `barcornertl${id}`, + layer: 'top', + anchor: ['top', 'left'], + exclusivity: 'normal', + visible: true, + child: RoundedCorner('topleft', { className: 'corner', }), + setup: enableClickthrough, +}); +export const BarCornerTopright = (id = '') => Widget.Window({ + name: `barcornertr${id}`, + layer: 'top', + anchor: ['top', 'right'], + exclusivity: 'normal', + visible: true, + child: RoundedCorner('topright', { className: 'corner', }), + setup: enableClickthrough, }); \ No newline at end of file diff --git a/.config/ags/widgets/bar/music.js b/.config/ags/widgets/bar/music.js index 92542fa71..3a3d3043e 100644 --- a/.config/ags/widgets/bar/music.js +++ b/.config/ags/widgets/bar/music.js @@ -6,10 +6,12 @@ import { AnimatedCircProg } from "../../lib/animatedcircularprogress.js"; import { showMusicControls } from '../../variables.js'; function trimTrackTitle(title) { - var cleanedTitle = title; - cleanedTitle = cleanedTitle.replace(/【[^】]*】/, ''); // Remove stuff like【C93】 at beginning - cleanedTitle = cleanedTitle.replace(/\[FREE DOWNLOAD\]/g, ''); // Remove F-777's [FREE DOWNLOAD] - return cleanedTitle.trim(); + cleanRegexes = [ + /【[^】]*】/, // Touhou n weeb stuff + /\[FREE DOWNLOAD\]/, // F-777 + ]; + cleanRegexes.forEach((expr) => cleanedTitle.replace(expr, '')); + return title; } const TrackProgress = () => { @@ -38,61 +40,66 @@ const moveToRelativeWorkspace = async (self, num) => { } } -export const ModuleMusic = () => Widget.EventBox({ // TODO: use cairo to make button bounce smaller on click - onScrollUp: (self) => moveToRelativeWorkspace(self, -1), - onScrollDown: (self) => moveToRelativeWorkspace(self, +1), - onPrimaryClickRelease: () => showMusicControls.setValue(!showMusicControls.value), - onSecondaryClickRelease: () => execAsync(['bash', '-c', 'playerctl next || playerctl position `bc <<< "100 * $(playerctl metadata mpris:length) / 1000000 / 100"` &']), - onMiddleClickRelease: () => execAsync('playerctl play-pause').catch(print), - child: Widget.Box({ - className: 'bar-group-margin bar-sides', - children: [ - Widget.Box({ - className: 'bar-group bar-group-standalone bar-group-pad-music spacing-h-10', - children: [ - Widget.Box({ // Wrap a box cuz overlay can't have margins itself - homogeneous: true, - children: [Widget.Overlay({ - child: Widget.Box({ - vpack: 'center', - className: 'bar-music-playstate', - homogeneous: true, - children: [Widget.Label({ - vpack: 'center', - className: 'bar-music-playstate-txt', - justification: 'center', - setup: (self) => self.hook(Mpris, label => { - const mpris = Mpris.getPlayer(''); - label.label = `${mpris !== null && mpris.playBackStatus == 'Playing' ? 'pause' : 'play_arrow'}`; - }), - })], - setup: (self) => self.hook(Mpris, label => { - const mpris = Mpris.getPlayer(''); - if (!mpris) return; - label.toggleClassName('bar-music-playstate-playing', mpris !== null && mpris.playBackStatus == 'Playing'); - label.toggleClassName('bar-music-playstate', mpris !== null || mpris.playBackStatus == 'Paused'); - }), - }), - overlays: [ - TrackProgress(), - ] - })] +export const ModuleMusic = () => { + // TODO: use cairo to make button bounce smaller on click, if that's possible + const playingState = Widget.Box({ // Wrap a box cuz overlay can't have margins itself + homogeneous: true, + children: [Widget.Overlay({ + child: Widget.Box({ + vpack: 'center', + className: 'bar-music-playstate', + homogeneous: true, + children: [Widget.Label({ + vpack: 'center', + className: 'bar-music-playstate-txt', + justification: 'center', + setup: (self) => self.hook(Mpris, label => { + const mpris = Mpris.getPlayer(''); + label.label = `${mpris !== null && mpris.playBackStatus == 'Playing' ? 'pause' : 'play_arrow'}`; }), - Widget.Scrollable({ - hexpand: true, - child: Widget.Label({ - className: 'txt-smallie txt-onSurfaceVariant', - setup: (self) => self.hook(Mpris, label => { - const mpris = Mpris.getPlayer(''); - if (mpris) - label.label = `${trimTrackTitle(mpris.trackTitle)} • ${mpris.trackArtists.join(', ')}`; - else - label.label = 'No media'; - }), - }) - }) - ] - }) - ] + })], + setup: (self) => self.hook(Mpris, label => { + const mpris = Mpris.getPlayer(''); + if (!mpris) return; + label.toggleClassName('bar-music-playstate-playing', mpris !== null && mpris.playBackStatus == 'Playing'); + label.toggleClassName('bar-music-playstate', mpris !== null || mpris.playBackStatus == 'Paused'); + }), + }), + overlays: [ + TrackProgress(), + ] + })] + }); + const trackTitle = Widget.Scrollable({ + hexpand: true, + child: Widget.Label({ + className: 'txt-smallie txt-onSurfaceVariant', + setup: (self) => self.hook(Mpris, label => { + const mpris = Mpris.getPlayer(''); + if (mpris) + label.label = `${trimTrackTitle(mpris.trackTitle)} • ${mpris.trackArtists.join(', ')}`; + else + label.label = 'No media'; + }), + }) }) -}); \ No newline at end of file + return Widget.EventBox({ + onScrollUp: (self) => moveToRelativeWorkspace(self, -1), + onScrollDown: (self) => moveToRelativeWorkspace(self, +1), + onPrimaryClickRelease: () => showMusicControls.setValue(!showMusicControls.value), + onSecondaryClickRelease: () => execAsync(['bash', '-c', 'playerctl next || playerctl position `bc <<< "100 * $(playerctl metadata mpris:length) / 1000000 / 100"` &']), + onMiddleClickRelease: () => execAsync('playerctl play-pause').catch(print), + child: Widget.Box({ + className: 'bar-group-margin bar-sides', + children: [ + Widget.Box({ + className: 'bar-group bar-group-standalone bar-group-pad-music spacing-h-10', + children: [ + playingState, + trackTitle, + ] + }) + ] + }) + }); +} \ No newline at end of file diff --git a/.config/ags/widgets/bar/rightspace.js b/.config/ags/widgets/bar/rightspace.js deleted file mode 100644 index 7370421a0..000000000 --- a/.config/ags/widgets/bar/rightspace.js +++ /dev/null @@ -1,81 +0,0 @@ -import App from 'resource:///com/github/Aylur/ags/app.js'; -import Widget from 'resource:///com/github/Aylur/ags/widget.js'; -import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; - -import Audio from 'resource:///com/github/Aylur/ags/service/audio.js'; -import SystemTray from 'resource:///com/github/Aylur/ags/service/systemtray.js'; -const { execAsync } = Utils; -import Indicator from '../../services/indicator.js'; -import { StatusIcons } from "../../lib/statusicons.js"; -import { RoundedCorner } from "../../lib/roundedcorner.js"; -import { Tray } from "./tray.js"; - -export const ModuleRightSpace = () => { - const barTray = Tray(); - const barStatusIcons = StatusIcons({ - className: 'bar-statusicons', - setup: (self) => self.hook(App, (self, currentName, visible) => { - if (currentName === 'sideright') { - self.toggleClassName('bar-statusicons-active', visible); - } - }), - }); - - return Widget.EventBox({ - onScrollUp: () => { - if (!Audio.speaker) return; - Audio.speaker.volume += 0.03; - Indicator.popup(1); - }, - onScrollDown: () => { - if (!Audio.speaker) return; - Audio.speaker.volume -= 0.03; - Indicator.popup(1); - }, - onHover: () => { barStatusIcons.toggleClassName('bar-statusicons-hover', true) }, - onHoverLost: () => { barStatusIcons.toggleClassName('bar-statusicons-hover', false) }, - onPrimaryClick: () => App.toggleWindow('sideright'), - onSecondaryClickRelease: () => execAsync(['bash', '-c', 'playerctl next || playerctl position `bc <<< "100 * $(playerctl metadata mpris:length) / 1000000 / 100"` &']).catch(print), - onMiddleClickRelease: () => execAsync('playerctl play-pause').catch(print), - child: Widget.Box({ - homogeneous: false, - children: [ - Widget.Box({ - hexpand: true, - className: 'spacing-h-5 txt', - children: [ - Widget.Box({ - hexpand: true, - className: 'spacing-h-5 txt', - children: [ - Widget.Box({ hexpand: true, }), - barTray, - Widget.Revealer({ - transition: 'slide_left', - revealChild: false, - attribute: { - 'count': 0, - 'update': (self, diff) => { - self.attribute.count += diff; - self.revealChild = (self.attribute.count > 0); - } - }, - child: Widget.Box({ - vpack: 'center', - className: 'separator-circle', - }), - setup: (self) => self - .hook(SystemTray, (self) => self.attribute.update(self, 1), 'added') - .hook(SystemTray, (self) => self.attribute.update(self, -1), 'removed') - , - }), - barStatusIcons, - ], - }), - ] - }), - RoundedCorner('topright', { className: 'corner-black' }) - ] - }) - }); -} \ No newline at end of file diff --git a/.config/ags/widgets/bar/leftspace.js b/.config/ags/widgets/bar/spaceleft.js similarity index 93% rename from .config/ags/widgets/bar/leftspace.js rename to .config/ags/widgets/bar/spaceleft.js index 254ffc254..4f2b8540a 100644 --- a/.config/ags/widgets/bar/leftspace.js +++ b/.config/ags/widgets/bar/spaceleft.js @@ -1,6 +1,5 @@ import App from 'resource:///com/github/Aylur/ags/app.js'; import Widget from 'resource:///com/github/Aylur/ags/widget.js'; -import { RoundedCorner } from "../../lib/roundedcorner.js"; import Brightness from '../../services/brightness.js'; import Indicator from '../../services/indicator.js'; @@ -37,7 +36,7 @@ const WindowTitle = async () => { const OptionalWindowTitleInstance = await WindowTitle(); -export const ModuleLeftSpace = () => Widget.EventBox({ +export default () => Widget.EventBox({ onScrollUp: () => { Indicator.popup(1); // Since the brightness and speaker are both on the same window Brightness.screen_value += 0.05; @@ -52,7 +51,7 @@ export const ModuleLeftSpace = () => Widget.EventBox({ child: Widget.Box({ homogeneous: false, children: [ - RoundedCorner('topleft', { className: 'corner-black' }), + Widget.Box({ className: 'bar-corner-spacing' }), Widget.Overlay({ overlays: [ Widget.Box({ hexpand: true }), diff --git a/.config/ags/widgets/bar/spaceright.js b/.config/ags/widgets/bar/spaceright.js new file mode 100644 index 000000000..dd69557f0 --- /dev/null +++ b/.config/ags/widgets/bar/spaceright.js @@ -0,0 +1,82 @@ +import App from 'resource:///com/github/Aylur/ags/app.js'; +import Widget from 'resource:///com/github/Aylur/ags/widget.js'; +import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; + +import Audio from 'resource:///com/github/Aylur/ags/service/audio.js'; +import SystemTray from 'resource:///com/github/Aylur/ags/service/systemtray.js'; +const { execAsync } = Utils; +import Indicator from '../../services/indicator.js'; +import { StatusIcons } from "../../lib/statusicons.js"; +import { Tray } from "./tray.js"; + +export default () => { + const barTray = Tray(); + const notifCounter = Widget.Revealer({ + transition: 'slide_left', + revealChild: false, + attribute: { + 'count': 0, + 'update': (self, diff) => { + self.attribute.count += diff; + self.revealChild = (self.attribute.count > 0); + } + }, + child: Widget.Box({ + vpack: 'center', + className: 'separator-circle', + }), + setup: (self) => self + .hook(SystemTray, (self) => self.attribute.update(self, 1), 'added') + .hook(SystemTray, (self) => self.attribute.update(self, -1), 'removed') + , + }); + const barStatusIcons = StatusIcons({ + className: 'bar-statusicons', + setup: (self) => self.hook(App, (self, currentName, visible) => { + if (currentName === 'sideright') { + self.toggleClassName('bar-statusicons-active', visible); + } + }), + }); + const actualContent = Widget.Box({ + hexpand: true, + className: 'spacing-h-5 txt', + children: [ + Widget.Box({ + hexpand: true, + className: 'spacing-h-5 txt', + children: [ + Widget.Box({ hexpand: true, }), + barTray, + notifCounter, + barStatusIcons, + ], + }), + ] + }); + + return Widget.EventBox({ + onScrollUp: () => { + if (!Audio.speaker) return; + Audio.speaker.volume += 0.03; + Indicator.popup(1); + }, + onScrollDown: () => { + if (!Audio.speaker) return; + Audio.speaker.volume -= 0.03; + Indicator.popup(1); + }, + onHover: () => { barStatusIcons.toggleClassName('bar-statusicons-hover', true) }, + onHoverLost: () => { barStatusIcons.toggleClassName('bar-statusicons-hover', false) }, + onPrimaryClick: () => App.toggleWindow('sideright'), + onSecondaryClickRelease: () => execAsync(['bash', '-c', 'playerctl next || playerctl position `bc <<< "100 * $(playerctl metadata mpris:length) / 1000000 / 100"` &']).catch(print), + onMiddleClickRelease: () => execAsync('playerctl play-pause').catch(print), + child: Widget.Box({ + homogeneous: false, + children: [ + actualContent, + Widget.Box({ className: 'bar-corner-spacing' }), + ] + }) + }); +} \ No newline at end of file diff --git a/.config/ags/widgets/desktopbackground/graph.js b/.config/ags/widgets/desktopbackground/graph.js deleted file mode 100644 index 5763472af..000000000 --- a/.config/ags/widgets/desktopbackground/graph.js +++ /dev/null @@ -1,83 +0,0 @@ -const { Gdk, Gtk } = imports.gi; -const Lang = imports.lang; -import { App, Service, Utils, Widget, SCREEN_HEIGHT, SCREEN_WIDTH } from '../../imports.js'; -const { execAsync, exec } = Utils; -const { Box, Label } = Widget; - -const NUM_OF_VERTICES = 30; -const NUM_OF_EDGES = 29; -// Vertices -var vertices = []; -for (var i = 0; i < NUM_OF_VERTICES; i++) { - vertices.push([ - Math.floor(Math.random() * SCREEN_WIDTH), - Math.floor(Math.random() * SCREEN_HEIGHT) - ]); -} -// Edges -function generateRandomEdges(numVertices, numEdges) { // TODO: make sure whole graph is connected - var edges = new Set(); - var vertices = []; - - // Generate vertices - for (var i = 0; i < numVertices; i++) { - vertices.push(i); - } - - // Generate random distinct edges - while (edges.size < numEdges) { - var randomVertex1 = vertices[Math.floor(Math.random() * numVertices)]; - var randomVertex2 = vertices[Math.floor(Math.random() * numVertices)]; - - // Ensure the two vertices are distinct and the edge doesn't already exist - if (randomVertex1 !== randomVertex2) { - var edge = [randomVertex1, randomVertex2].sort(); - edges.add(edge.join(',')); - } - } - - return Array.from(edges).map(edge => edge.split(',').map(Number)); -} - -var edges = generateRandomEdges(NUM_OF_VERTICES, NUM_OF_EDGES); - -export default () => Box({ - hpack: 'fill', - vpack: 'fill', - homogeneous: true, - children: [ - Widget.DrawingArea({ - className: 'bg-graph', - setup: (area) => { - area.connect('draw', Lang.bind(area, (area, cr) => { - // area.set_size_request(SCREEN_WIDTH, SCREEN_HEIGHT); - // console.log('allocated width/height:', area.get_allocated_width(), '/', area.get_allocated_height()) - const styleContext = area.get_style_context(); - const color = styleContext.get_property('color', Gtk.StateFlags.NORMAL); - const backgroundColor = styleContext.get_property('background-color', Gtk.StateFlags.NORMAL); - const radius = area.get_style_context().get_property('border-radius', Gtk.StateFlags.NORMAL); - const borderWidth = area.get_style_context().get_border(Gtk.StateFlags.NORMAL).left; // ur going to write border-width: something anyway - - cr.setSourceRGBA(backgroundColor.red, backgroundColor.green, backgroundColor.blue, backgroundColor.alpha); - cr.rectangle(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT) - cr.fill(); - cr.setSourceRGBA(color.red, color.green, color.blue, color.alpha); - // Draw edges - cr.setLineWidth(borderWidth); - console.log("line width:", borderWidth); - for (var i = 0; i < NUM_OF_EDGES; i++) { - console.log(vertices[edges[i][0]][0], vertices[edges[i][0]][1], '->', vertices[edges[i][1]][0], vertices[edges[i][1]][1]) - cr.moveTo(vertices[edges[i][0]][0], vertices[edges[i][0]][1]); - cr.lineTo(vertices[edges[i][1]][0], vertices[edges[i][1]][1]); - cr.stroke(); - } - // Draw vertices - for (var i = 0; i < NUM_OF_VERTICES; i++) { - cr.arc(vertices[i][0], vertices[i][1], radius, 0, 2 * Math.PI) - cr.fill() - } - })) - } - }) - ] -}) diff --git a/.config/ags/widgets/desktopbackground/main.js b/.config/ags/widgets/desktopbackground/main.js index 2a90d7df8..804746279 100644 --- a/.config/ags/widgets/desktopbackground/main.js +++ b/.config/ags/widgets/desktopbackground/main.js @@ -1,11 +1,7 @@ -const { Gdk, Gtk } = imports.gi; import Widget from 'resource:///com/github/Aylur/ags/widget.js'; -import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; -const { execAsync, exec } = Utils; import TimeAndLaunchesWidget from './timeandlaunches.js' import SystemWidget from './system.js' -import GraphWidget from './graph.js' export default () => Widget.Window({ name: 'desktopbackground', @@ -19,7 +15,6 @@ export default () => Widget.Window({ vexpand: true, }), overlays: [ - // GraphWidget(), TimeAndLaunchesWidget(), SystemWidget(), ], diff --git a/.config/ags/widgets/indicators/indicatorvalues.js b/.config/ags/widgets/indicators/indicatorvalues.js index d12d8c906..2b2980f63 100644 --- a/.config/ags/widgets/indicators/indicatorvalues.js +++ b/.config/ags/widgets/indicators/indicatorvalues.js @@ -1,7 +1,7 @@ // This file is for brightness/volume indicators import Widget from 'resource:///com/github/Aylur/ags/widget.js'; import Audio from 'resource:///com/github/Aylur/ags/service/audio.js'; -const { Box, Label, ProgressBar, Revealer } = Widget; +const { Box, Label, ProgressBar } = Widget; import { MarginRevealer } from '../../lib/advancedwidgets.js'; import Brightness from '../../services/brightness.js'; import Indicator from '../../services/indicator.js'; @@ -12,7 +12,7 @@ const OsdValue = (name, labelSetup, progressSetup, props = {}) => { className: 'osd-label', label: `${name}`, }); - const valueNumber =Label({ + const valueNumber = Label({ hexpand: false, className: 'osd-value-txt', setup: labelSetup, }); @@ -44,51 +44,44 @@ const OsdValue = (name, labelSetup, progressSetup, props = {}) => { }); } -const brightnessIndicator = OsdValue('Brightness', - (self) => self - .hook(Brightness, self => { +export default () => { + const brightnessIndicator = OsdValue('Brightness', + (self) => self.hook(Brightness, self => { self.label = `${Math.round(Brightness.screen_value * 100)}`; - }, 'notify::screen-value') - , - (self) => self - .hook(Brightness, (progress) => { + }, 'notify::screen-value'), + (self) => self.hook(Brightness, (progress) => { const updateValue = Brightness.screen_value; progress.value = updateValue; - }, 'notify::screen-value') - , -) + }, 'notify::screen-value'), + ) -const volumeIndicator = OsdValue('Volume', - (self) => self - .hook(Audio, (label) => { + const volumeIndicator = OsdValue('Volume', + (self) => self.hook(Audio, (label) => { label.label = `${Math.round(Audio.speaker?.volume * 100)}`; - }) - , - (self) => self - .hook(Audio, (progress) => { + }), + (self) => self.hook(Audio, (progress) => { const updateValue = Audio.speaker?.volume; if (!isNaN(updateValue)) progress.value = updateValue; + }), + ); + return MarginRevealer({ + transition: 'slide_down', + showClass: 'osd-show', + hideClass: 'osd-hide', + extraSetup: (self) => self + .hook(Indicator, (revealer, value) => { + if (value > -1) revealer.attribute.show(); + else revealer.attribute.hide(); + }, 'popup') + , + child: Box({ + hpack: 'center', + vertical: false, + className: 'spacing-h--10', + children: [ + brightnessIndicator, + volumeIndicator, + ] }) - , -); - -export default () => MarginRevealer({ - transition: 'slide_down', - showClass: 'osd-show', - hideClass: 'osd-hide', - extraSetup: (self) => self - .hook(Indicator, (revealer, value) => { - if (value > -1) revealer.attribute.show(); - else revealer.attribute.hide(); - }, 'popup') - , - child: Box({ - hpack: 'center', - vertical: false, - className: 'spacing-h--10', - children: [ - brightnessIndicator, - volumeIndicator, - ] - }) -}); \ No newline at end of file + }); +} \ No newline at end of file diff --git a/.config/ags/widgets/indicators/main.js b/.config/ags/widgets/indicators/main.js index b7aa55900..db3fc4c8c 100644 --- a/.config/ags/widgets/indicators/main.js +++ b/.config/ags/widgets/indicators/main.js @@ -5,7 +5,7 @@ import MusicControls from './musiccontrols.js'; import ColorScheme from './colorscheme.js'; import NotificationPopups from './notificationpopups.js'; -export default (monitor) => Widget.Window({ +export default (monitor = 0) => Widget.Window({ name: `indicator${monitor}`, monitor, className: 'indicator', diff --git a/.config/ags/widgets/indicators/musiccontrols.js b/.config/ags/widgets/indicators/musiccontrols.js index be51cc963..70faf3531 100644 --- a/.config/ags/widgets/indicators/musiccontrols.js +++ b/.config/ags/widgets/indicators/musiccontrols.js @@ -32,17 +32,13 @@ function isRealPlayer(player) { ); } -export const getPlayer = (name = PREFERRED_PLAYER) => { - return Mpris.getPlayer(name) || Mpris.players[0] || null; -} - +export const getPlayer = (name = PREFERRED_PLAYER) => Mpris.getPlayer(name) || Mpris.players[0] || null; function lengthStr(length) { const min = Math.floor(length / 60); const sec = Math.floor(length % 60); const sec0 = sec < 10 ? '0' : ''; return `${min}:${sec0}${sec}`; } - function fileExists(filePath) { let file = Gio.File.new_for_path(filePath); return file.query_exists(null); @@ -54,17 +50,11 @@ function detectMediaSource(link) { return '󰈹 Firefox' return "󰈣 File"; } - // Remove protocol if present let url = link.replace(/(^\w+:|^)\/\//, ''); - // Extract the domain name let domain = url.match(/(?:[a-z]+\.)?([a-z]+\.[a-z]+)/i)[1]; - - if (domain == 'ytimg.com') - return '󰗃 Youtube'; - if (domain == 'discordapp.net') - return '󰙯 Discord'; - if (domain == 'sndcdn.com') - return '󰓀 SoundCloud'; + if (domain == 'ytimg.com') return '󰗃 Youtube'; + if (domain == 'discordapp.net') return '󰙯 Discord'; + if (domain == 'sndcdn.com') return '󰓀 SoundCloud'; return domain; } @@ -72,15 +62,19 @@ const DEFAULT_MUSIC_FONT = 'Gabarito, sans-serif'; function getTrackfont(player) { const title = player.trackTitle; const artists = player.trackArtists.join(' '); - if (artists.includes('TANO*C') || artists.includes('USAO') || artists.includes('Kobaryo')) return 'Chakra Petch'; // Rigid square replacement - if (title.includes('東方')) return 'Crimson Text, serif'; // Serif for Touhou stuff + if (artists.includes('TANO*C') || artists.includes('USAO') || artists.includes('Kobaryo')) + return 'Chakra Petch'; // Rigid square replacement + if (title.includes('東方')) + return 'Crimson Text, serif'; // Serif for Touhou stuff return DEFAULT_MUSIC_FONT; } function trimTrackTitle(title) { - var cleanedTitle = title; - cleanedTitle = cleanedTitle.replace(/【[^】]*】/, ''); // Remove stuff like【C93】 at beginning - cleanedTitle = cleanedTitle.replace(/\[FREE DOWNLOAD\]/g, ''); // Remove F-777's [FREE DOWNLOAD] - return cleanedTitle.trim(); + cleanRegexes = [ + /【[^】]*】/, // Touhou n weeb stuff + /\[FREE DOWNLOAD\]/, // F-777 + ]; + cleanRegexes.forEach((expr) => cleanedTitle.replace(expr, '')); + return title; } const TrackProgress = ({ player, ...rest }) => { diff --git a/.config/ags/widgets/onscreenkeyboard/onscreenkeyboard.js b/.config/ags/widgets/onscreenkeyboard/onscreenkeyboard.js index 7cc93ac16..e77b91788 100644 --- a/.config/ags/widgets/onscreenkeyboard/onscreenkeyboard.js +++ b/.config/ags/widgets/onscreenkeyboard/onscreenkeyboard.js @@ -18,7 +18,7 @@ execAsync(`ydotoold`).catch(print); // Start ydotool daemon function releaseAllKeys() { const keycodes = Array.from(Array(249).keys()); execAsync([`ydotool`, `key`, ...keycodes.map(keycode => `${keycode}:0`)]) - .then(console.log('Released all keys')) + .then(console.log('[OSK] Released all keys')) .catch(print); } var modsPressed = false; diff --git a/.config/ags/widgets/overview/actions.js b/.config/ags/widgets/overview/actions.js index c5a429f53..766cf4542 100644 --- a/.config/ags/widgets/overview/actions.js +++ b/.config/ags/widgets/overview/actions.js @@ -6,7 +6,6 @@ function moveClientToWorkspace(address, workspace) { } export function dumpToWorkspace(from, to) { - console.log('dump', from, to); if (from == to) return; Hyprland.clients.forEach(client => { if (client.workspace.id == from) { diff --git a/.config/ags/widgets/overview/miscfunctions.js b/.config/ags/widgets/overview/miscfunctions.js index 0a6ecc40d..42e2572f3 100644 --- a/.config/ags/widgets/overview/miscfunctions.js +++ b/.config/ags/widgets/overview/miscfunctions.js @@ -53,7 +53,7 @@ export function launchCustomCommand(command) { execAsync([`bash`, `-c`, `systemctl suspend`]).catch(print); } else if (args[0] == '>logout') { // Log out - execAsync([`bash`, `-c`, `killall Hyprland`]).catch(print); + execAsync([`bash`, `-c`, `loginctl terminate-user $USER`]).catch(print); } } diff --git a/.config/ags/widgets/overview/windowcontent.js b/.config/ags/widgets/overview/windowcontent.js index da1907ee4..f10dd7845 100644 --- a/.config/ags/widgets/overview/windowcontent.js +++ b/.config/ags/widgets/overview/windowcontent.js @@ -166,7 +166,7 @@ export const SearchAndWindows = () => { _appSearchResults = Applications.query(text); // Calculate - if (startsWithNumber(text)) { // Eval on typing is dangerous, this is a small workaround. + if (startsWithNumber(text)) { // Eval on typing is dangerous; this is a small workaround. try { const fullResult = eval(text); resultsBox.add(CalculationResultButton({ result: fullResult, text: text })); diff --git a/.config/ags/widgets/screencorners/main.js b/.config/ags/widgets/screencorners/main.js index 74e9dd52f..42a8a5283 100644 --- a/.config/ags/widgets/screencorners/main.js +++ b/.config/ags/widgets/screencorners/main.js @@ -1,43 +1,16 @@ -import Cairo from 'gi://cairo?version=1.0'; import Widget from 'resource:///com/github/Aylur/ags/widget.js'; -import { RoundedCorner } from "../../lib/roundedcorner.js"; +import { RoundedCorner, dummyRegion, enableClickthrough } from "../../lib/roundedcorner.js"; -const dummyRegion = new Cairo.Region(); -const enableClickthrough = (self) => self.input_shape_combine_region(dummyRegion); - -export const CornerTopleft = () => Widget.Window({ - name: 'cornertl', - layer: 'top', - anchor: ['top', 'left'], - exclusivity: 'normal', - visible: true, - child: RoundedCorner('topleft', { className: 'corner', }), - setup: enableClickthrough, -}); -export const CornerTopright = () => Widget.Window({ - name: 'cornertr', - layer: 'top', - anchor: ['top', 'right'], - exclusivity: 'normal', - visible: true, - child: RoundedCorner('topright', { className: 'corner', }), - setup: enableClickthrough, -}); -export const CornerBottomleft = () => Widget.Window({ - name: 'cornerbl', - layer: 'top', - anchor: ['bottom', 'left'], - exclusivity: 'ignore', - visible: true, - child: RoundedCorner('bottomleft', { className: 'corner-black', }), - setup: enableClickthrough, -}); -export const CornerBottomright = () => Widget.Window({ - name: 'cornerbr', - layer: 'top', - anchor: ['bottom', 'right'], - exclusivity: 'ignore', - visible: true, - child: RoundedCorner('bottomright', { className: 'corner-black', }), - setup: enableClickthrough, -}); +export default (monitor = 0, where = 'bottom left') => { + const positionString = where.replace(/\s/, ""); // remove space + return Widget.Window({ + monitor, + name: `corner${positionString}${monitor}`, + layer: 'overlay', + anchor: where.split(' '), + exclusivity: 'ignore', + visible: true, + child: RoundedCorner(positionString, { className: 'corner-black', }), + setup: enableClickthrough, + }); +} \ No newline at end of file diff --git a/.config/ags/widgets/session/sessionscreen.js b/.config/ags/widgets/session/sessionscreen.js index a67fc93d7..0b760fd21 100644 --- a/.config/ags/widgets/session/sessionscreen.js +++ b/.config/ags/widgets/session/sessionscreen.js @@ -63,7 +63,7 @@ export default () => { // lock, logout, sleep // const lockButton = SessionButton('Lock', 'lock', () => { App.closeWindow('session'); execAsync('gtklock') }); const lockButton = SessionButton('Lock', 'lock', () => { App.closeWindow('session'); execAsync('swaylock') }); - const logoutButton = SessionButton('Logout', 'logout', () => { App.closeWindow('session'); execAsync(['bash', '-c', 'killall Hyprland']) }); + const logoutButton = SessionButton('Logout', 'logout', () => { App.closeWindow('session'); execAsync(['bash', '-c', 'loginctl terminate-user $USER']) }); const sleepButton = SessionButton('Sleep', 'sleep', () => { App.closeWindow('session'); execAsync('systemctl suspend') }); // hibernate, shutdown, reboot const hibernateButton = SessionButton('Hibernate', 'downloading', () => { App.closeWindow('session'); execAsync('systemctl hibernate') }); diff --git a/.config/ags/widgets/sideright/quicktoggles.js b/.config/ags/widgets/sideright/quicktoggles.js index 4a3d26575..9ba354ddf 100644 --- a/.config/ags/widgets/sideright/quicktoggles.js +++ b/.config/ags/widgets/sideright/quicktoggles.js @@ -11,7 +11,6 @@ import { MaterialIcon } from '../../lib/materialicon.js'; function expandTilde(path) { if (path.startsWith('~')) { - console.log(GLib.get_home_dir() + path.slice(1)); return GLib.get_home_dir() + path.slice(1); } else { return path; @@ -120,8 +119,6 @@ export const ModuleInvertColors = async (props = {}) => { Hyprland.sendMessage('j/getoption decoration:screen_shader') .then((output) => { const shaderPath = JSON.parse(output)["str"].trim(); - console.log(output) - console.log(shaderPath) if (shaderPath != "[[EMPTY]]" && shaderPath != "") { execAsync(['bash', '-c', `hyprctl keyword decoration:screen_shader '[[EMPTY]]'`]).catch(print); button.toggleClassName('sidebar-button-active', false);