should add multimonitor support

This commit is contained in:
end-4
2024-01-17 18:23:35 +07:00
parent 94a5603cd2
commit 29d109770d
23 changed files with 341 additions and 410 deletions
+28 -20
View File
@@ -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),
};
+8 -9
View File
@@ -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;
-1
View File
@@ -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();
},
+4
View File
@@ -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,
+5
View File
@@ -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;
+18
View File
@@ -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);
+59 -36
View File
@@ -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,
});
+67 -60
View File
@@ -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';
}),
})
})
});
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,
]
})
]
})
});
}
-81
View File
@@ -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' })
]
})
});
}
@@ -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 }),
+82
View File
@@ -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' }),
]
})
});
}
@@ -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()
}
}))
}
})
]
})
@@ -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(),
],
@@ -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,
]
})
});
});
}
+1 -1
View File
@@ -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',
+14 -20
View File
@@ -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 }) => {
@@ -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;
-1
View File
@@ -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) {
@@ -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);
}
}
@@ -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 }));
+14 -41
View File
@@ -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,
});
}
+1 -1
View File
@@ -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') });
@@ -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);