Compare commits

..

2 commits

41 changed files with 266 additions and 174 deletions

View file

@ -1,22 +1,25 @@
import { exec, execAsync } from 'resource:///com/github/Aylur/ags/utils.js'; import { App, Utils } from './imports.js';
import { Powermenu } from './js/powermenu.js';
import { Bar } from './js/bar/main.js'; import { Powermenu } from './js/powermenu.js';
import { NotificationCenter } from './js/notifications/center.js'; import { Bar } from './js/bar/main.js';
import { NotificationCenter } from './js/notifications/center.js';
import { NotificationsPopupList } from './js/notifications/popup.js' import { NotificationsPopupList } from './js/notifications/popup.js'
import { Calendar } from './js/date.js'; import { Calendar } from './js/date.js';
import { QuickSettings } from './js/quick-settings/main.js'; import { QuickSettings } from './js/quick-settings/main.js';
import Overview from './js/overview/main.js'; import Overview from './js/overview/main.js';
import AppLauncher from './js/applauncher/main.js'; import AppLauncher from './js/applauncher/main.js';
import { Closer, closeAll } from './js/misc/closer.js'; import { Closer, closeAll } from './js/misc/closer.js';
ags.App.closeAll = () => closeAll(); globalThis.closeAll = () => closeAll();
const scss = ags.App.configDir + '/scss/main.scss';
const css = ags.App.configDir + '/style.css';
exec(`sassc ${scss} ${css}`); const scss = App.configDir + '/scss/main.scss';
const css = App.configDir + '/style.css';
Utils.exec(`sassc ${scss} ${css}`);
Utils.execAsync(['bash', '-c', '$AGS_PATH/startup.sh']).catch(print);
execAsync(['bash', '-c', '$AGS_PATH/startup.sh']).catch(print);
export default { export default {
style: css, style: css,

21
config/ags/imports.js Normal file
View file

@ -0,0 +1,21 @@
const resource = file => `resource:///com/github/Aylur/ags/${file}.js`;
const require = async file => (await import(resource(file))).default;
const service = async file => (await require(`service/${file}`)).instance;
export const App = await require('app');
App.connect = (...args) => App.instance.connect(...args);
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 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');

View file

@ -1,6 +1,5 @@
const { App } = ags; import { App, Applications, Widget } from '../../imports.js';
const { Applications } = ags.Service; const { Label, Box, Icon, Button, Scrollable, Entry, Window, EventBox } = Widget;
const { Label, Box, Icon, Button, Scrollable, Entry, Window, EventBox } = ags.Widget;
import { Separator } from '../misc/separator.js'; import { Separator } from '../misc/separator.js';
import { PopUp } from '../misc/popup.js'; import { PopUp } from '../misc/popup.js';
@ -12,6 +11,7 @@ const icons = {
} }
}; };
const AppItem = (app, window) => { const AppItem = (app, window) => {
if (app.app.get_string('Icon') == 'Nextcloud') if (app.app.get_string('Icon') == 'Nextcloud')
return; return;

View file

@ -1,5 +1,5 @@
const { Audio } = ags.Service; import { Audio, Widget } from '../../imports.js';
const { Label, Box, Icon, Stack, Button, Slider } = ags.Widget; const { Label, Box, Icon } = Widget;
import { Separator } from '../misc/separator.js'; import { Separator } from '../misc/separator.js';
import { EventBox } from '../misc/cursorbox.js'; import { EventBox } from '../misc/cursorbox.js';
@ -12,12 +12,13 @@ const items = {
0: 'audio-volume-muted-symbolic', 0: 'audio-volume-muted-symbolic',
}; };
const SpeakerIndicator = params => Icon({ const SpeakerIndicator = params => Icon({
...params, ...params,
icon: '', icon: '',
connections: [[Audio, icon => { connections: [[Audio, icon => {
if (Audio.speaker) { if (Audio.speaker) {
if (Audio.speaker.isMuted) { if (Audio.speaker.stream.isMuted) {
icon.icon = items[0]; icon.icon = items[0];
} }
else { else {

View file

@ -1,5 +1,5 @@
const { Battery } = ags.Service; import { Battery, Widget } from '../../imports.js';
const { Label, Icon, Stack, Box } = ags.Widget; const { Label, Icon, Stack, Box } = Widget;
import { Separator } from '../misc/separator.js'; import { Separator } from '../misc/separator.js';
@ -16,6 +16,7 @@ const icons = charging => ([
})], })],
]); ]);
const Indicators = charging => Stack({ const Indicators = charging => Stack({
items: icons(charging), items: icons(charging),
connections: [[Battery, stack => { connections: [[Battery, stack => {

View file

@ -1,8 +1,10 @@
const { ProgressBar, Overlay, Box } = ags.Widget; import { Utils, Widget } from '../../imports.js';
const { execAsync } = ags.Utils; const { ProgressBar, Overlay, Box } = Widget;
import { Separator } from '../misc/separator.js'; import { Separator } from '../misc/separator.js';
import { Heart } from './heart.js'; import { Heart } from './heart.js';
export const Brightness = Overlay({ export const Brightness = Overlay({
setup: widget => { setup: widget => {
widget.set_tooltip_text('Brightness'); widget.set_tooltip_text('Brightness');
@ -11,7 +13,7 @@ export const Brightness = Overlay({
className: 'toggle-off brightness', className: 'toggle-off brightness',
connections: [ connections: [
[200, progress => { [200, progress => {
execAsync('brightnessctl get').then(out => { Utils.execAsync('brightnessctl get').then(out => {
let br = out / 255; let br = out / 255;
if (br > 0.33) { if (br > 0.33) {
progress.value = br; progress.value = br;

View file

@ -1,9 +1,13 @@
const { Box, Label } = ags.Widget; import { App, Widget } from '../../imports.js';
const { toggleWindow } = ags.App; const { Box, Label } = Widget;
const { DateTime } = imports.gi.GLib; const { toggleWindow } = App;
import GLib from 'gi://GLib';
const { DateTime } = GLib;
import { EventBox } from '../misc/cursorbox.js'; import { EventBox } from '../misc/cursorbox.js';
const ClockModule = ({ const ClockModule = ({
interval = 1000, interval = 1000,
...params ...params
@ -22,7 +26,7 @@ export const Clock = EventBox({
className: 'toggle-off', className: 'toggle-off',
onPrimaryClickRelease: () => toggleWindow('calendar'), onPrimaryClickRelease: () => toggleWindow('calendar'),
connections: [ connections: [
[ags.App, (box, windowName, visible) => { [App, (box, windowName, visible) => {
if (windowName == 'calendar') { if (windowName == 'calendar') {
box.toggleClassName('toggle-on', visible); box.toggleClassName('toggle-on', visible);
} }

View file

@ -1,6 +1,6 @@
const { Hyprland } = ags.Service; import { Widget, Hyprland } from '../../imports.js';
const { Label } = ags.Widget; const { Label } = Widget;
const { Gtk } = imports.gi;
export const CurrentWindow = Label({ export const CurrentWindow = Label({
style: 'color: #CBA6F7; font-size: 18px', style: 'color: #CBA6F7; font-size: 18px',

View file

@ -1,7 +1,9 @@
const { Window, CenterBox, EventBox, Button } = ags.Widget; import { Widget, App } from '../../imports.js';
const { openWindow } = ags.App; const { CenterBox, EventBox } = Widget;
const { Gtk, Gdk } = imports.gi; const { openWindow } = App;
const display = Gdk.Display.get_default();
import Gtk from 'gi://Gtk';
export const Gesture = ({ export const Gesture = ({
child, child,
@ -19,7 +21,7 @@ export const Gesture = ({
], ],
connections: [ connections: [
[gesture, box => { [gesture, _ => {
const velocity = gesture.get_velocity()[1]; const velocity = gesture.get_velocity()[1];
if (velocity < -100) if (velocity < -100)
openWindow('quick-settings'); openWindow('quick-settings');

View file

@ -1,10 +1,11 @@
const { Box, Label } = ags.Widget; import { Utils, Widget } from '../../imports.js';
const { subprocess, execAsync } = ags.Utils; const { Box, Label } = Widget;
const deflisten = subprocess; const { subprocess, execAsync } = Utils;
import { EventBox } from '../misc/cursorbox.js'; import { EventBox } from '../misc/cursorbox.js';
deflisten(
subprocess(
['bash', '-c', 'tail -f /home/matt/.config/.heart'], ['bash', '-c', 'tail -f /home/matt/.config/.heart'],
(output) => { (output) => {
Heart.child.children[0].label = ' ' + output; Heart.child.children[0].label = ' ' + output;

View file

@ -1,4 +1,5 @@
const { Window, CenterBox, Box } = ags.Widget; import { Widget } from '../../imports.js';
const { Window, CenterBox, Box } = Widget;
import { Separator } from '../misc/separator.js'; import { Separator } from '../misc/separator.js';
import { CurrentWindow } from './current-window.js'; import { CurrentWindow } from './current-window.js';
@ -14,6 +15,7 @@ import { Brightness } from './brightness.js';
import { AudioIndicator } from './audio.js'; import { AudioIndicator } from './audio.js';
import { Gesture } from './gesture.js'; import { Gesture } from './gesture.js';
export const Bar = Window({ export const Bar = Window({
name: 'bar', name: 'bar',
layer: 'overlay', layer: 'overlay',

View file

@ -1,15 +1,16 @@
const { Box, Label, Icon } = ags.Widget; import { App, Notifications, Widget } from '../../imports.js';
const { toggleWindow } = ags.App; const { Box, Label, Icon } = Widget;
const { Notifications } = ags.Service; const { toggleWindow } = App;
import { Separator } from '../misc/separator.js'; import { Separator } from '../misc/separator.js';
import { EventBox } from '../misc/cursorbox.js'; import { EventBox } from '../misc/cursorbox.js';
export const NotifButton = EventBox({ export const NotifButton = EventBox({
className: 'toggle-off', className: 'toggle-off',
onPrimaryClickRelease: () => toggleWindow('notification-center'), onPrimaryClickRelease: () => toggleWindow('notification-center'),
connections: [ connections: [
[ags.App, (box, windowName, visible) => { [App, (box, windowName, visible) => {
if (windowName == 'notification-center') { if (windowName == 'notification-center') {
box.toggleClassName('toggle-on', visible); box.toggleClassName('toggle-on', visible);
} }

View file

@ -1,10 +1,11 @@
const { Box, Label } = ags.Widget; import { Utils, Widget } from '../../imports.js';
const { subprocess } = ags.Utils; const { Box, Label } = Widget;
const deflisten = subprocess; const { subprocess } = Utils;
import { EventBox } from '../misc/cursorbox.js'; import { EventBox } from '../misc/cursorbox.js';
deflisten(
subprocess(
['bash', '-c', '$AGS_PATH/osk-toggle.sh getState'], ['bash', '-c', '$AGS_PATH/osk-toggle.sh getState'],
(output) => { (output) => {
if (output == 'Running') { if (output == 'Running') {

View file

@ -1,13 +1,15 @@
const { Box, Label } = ags.Widget; import { Widget, App } from '../../imports.js';
const { toggleWindow } = ags.App; const { Box, Label } = Widget;
const { toggleWindow } = App;
import { EventBox } from '../misc/cursorbox.js'; import { EventBox } from '../misc/cursorbox.js';
export const QsToggle = EventBox({ export const QsToggle = EventBox({
className: 'toggle-off', className: 'toggle-off',
onPrimaryClickRelease: () => toggleWindow('quick-settings'), onPrimaryClickRelease: () => toggleWindow('quick-settings'),
connections: [ connections: [
[ags.App, (box, windowName, visible) => { [App, (box, windowName, visible) => {
if (windowName == 'quick-settings') { if (windowName == 'quick-settings') {
box.toggleClassName('toggle-on', visible); box.toggleClassName('toggle-on', visible);
} }

View file

@ -1,9 +1,11 @@
const { SystemTray } = ags.Service; import { SystemTray, Widget } from '../../imports.js';
const { Box, Revealer, Icon, MenuItem } = ags.Widget; const { Box, Revealer, Icon, MenuItem } = Widget;
const { Gtk } = imports.gi;
import Gtk from 'gi://Gtk';
import { Separator } from '../misc/separator.js'; import { Separator } from '../misc/separator.js';
const SysTrayItem = item => MenuItem({ const SysTrayItem = item => MenuItem({
className: 'tray-item', className: 'tray-item',
child: Icon({ child: Icon({
@ -23,7 +25,7 @@ export const SysTray = Revealer({
}]], }]],
child: Box({ child: Box({
children: [ children: [
ags.Widget({ Widget({
type: Gtk.MenuBar, type: Gtk.MenuBar,
className: 'sys-tray', className: 'sys-tray',
properties: [ properties: [

View file

@ -1,8 +1,10 @@
const { Box, Label } = ags.Widget; import { Utils, Widget } from '../../imports.js';
const { subprocess } = ags.Utils; const { Box, Label } = Widget;
const { subprocess } = Utils;
import { EventBox } from '../misc/cursorbox.js'; import { EventBox } from '../misc/cursorbox.js';
export const TabletToggle = EventBox({ export const TabletToggle = EventBox({
className: 'toggle-off', className: 'toggle-off',
onPrimaryClickRelease: function() { onPrimaryClickRelease: function() {

View file

@ -1,9 +1,10 @@
const { Hyprland, Applications } = ags.Service; import { Hyprland, Utils, Widget } from '../../imports.js';
const { execAsync } = ags.Utils; const { Box, Label, Revealer } = Widget;
const { Box, Button, Label, Revealer } = ags.Widget; const { execAsync } = Utils;
import { EventBox } from '../misc/cursorbox.js'; import { EventBox } from '../misc/cursorbox.js';
const Workspace = ({ i } = {}) => const Workspace = ({ i } = {}) =>
Revealer({ Revealer({
transition: "slide_right", transition: "slide_right",

View file

@ -1,9 +1,13 @@
const { Box, Label, Window } = ags.Widget; import { Widget } from '../imports.js';
const { Gtk } = imports.gi; const { Box, Label, Window } = Widget;
const { DateTime } = imports.gi.GLib;
import Gtk from 'gi://Gtk';
import GLib from 'gi://GLib';
const { DateTime } = GLib;
import { PopUp } from './misc/popup.js'; import { PopUp } from './misc/popup.js';
const Divider = () => Box({ const Divider = () => Box({
className: 'divider', className: 'divider',
vertical: true, vertical: true,
@ -59,7 +63,7 @@ const Time = () => Box({
const CalendarWidget = () => Box({ const CalendarWidget = () => Box({
className: 'cal-box', className: 'cal-box',
child: ags.Widget({ child: Widget({
type: Gtk.Calendar, type: Gtk.Calendar,
showDayNames: true, showDayNames: true,
showHeading: true, showHeading: true,

View file

@ -1,13 +1,15 @@
const { Box, Overlay, EventBox } = ags.Widget; import { Widget } from '../../imports.js';
const { Gtk } = imports.gi; const { Box, Overlay, EventBox } = Widget;
import Gtk from 'gi://Gtk';
const MAX_OFFSET = 200; const MAX_OFFSET = 200;
const OFFSCREEN = 500; const OFFSCREEN = 500;
const TRANSITION = 'transition: margin 0.5s ease, opacity 3s ease;'; const TRANSITION = 'transition: margin 0.5s ease, opacity 3s ease;';
export default ({ properties, connections, params } = {}) => { export default ({ properties, connections, params } = {}) => {
let widget = EventBox(); let widget = EventBox();
let gesture = Gtk.GestureDrag.new(widget) let gesture = Gtk.GestureDrag.new(widget)
widget.child = Overlay({ widget.child = Overlay({

View file

@ -1,7 +1,8 @@
const { execAsync, lookUpIcon } = ags.Utils; import { Mpris, Utils, Widget } from '../../imports.js';
const { Mpris } = ags.Service; const { Button, Icon, Label, Stack, Slider, CenterBox, Box } = Widget;
const { Button, Icon, Label, Stack, Slider, CenterBox, Box } = ags.Widget; const { execAsync, lookUpIcon } = Utils;
const { Gdk } = imports.gi;
import Gdk from 'gi://Gdk';
const display = Gdk.Display.get_default(); const display = Gdk.Display.get_default();
import { EventBox } from '../misc/cursorbox.js'; import { EventBox } from '../misc/cursorbox.js';
@ -27,6 +28,7 @@ const icons = {
}, },
} }
export const CoverArt = (player, params) => CenterBox({ export const CoverArt = (player, params) => CenterBox({
...params, ...params,
vertical: true, vertical: true,

View file

@ -1,10 +1,11 @@
const { Mpris } = ags.Service; import { Mpris, Variable, Widget } from '../../imports.js';
const { Box, CenterBox, Label } = ags.Widget; const { Box, CenterBox, Label } = Widget;
import * as mpris from './mpris.js'; import * as mpris from './mpris.js';
import PlayerGesture from './gesture.js'; import PlayerGesture from './gesture.js';
import { Separator } from '../misc/separator.js'; import { Separator } from '../misc/separator.js';
const Top = player => Box({ const Top = player => Box({
className: 'top', className: 'top',
halign: 'start', halign: 'start',
@ -97,7 +98,7 @@ export default () => Box({
return; return;
const player = Mpris.getPlayer(busName); const player = Mpris.getPlayer(busName);
player.colors = ags.Variable(); player.colors = Variable();
overlay._players.set(busName, PlayerBox(player)); overlay._players.set(busName, PlayerBox(player));
let result = []; let result = [];

View file

@ -1,5 +1,6 @@
const { Window, EventBox } = ags.Widget; import { App, Widget } from '../../imports.js';
const { closeWindow } = ags.App; const { Window, EventBox } = Widget;
const { closeWindow } = App;
const ALWAYS_OPEN = [ const ALWAYS_OPEN = [
'closer', 'closer',
@ -7,11 +8,12 @@ const ALWAYS_OPEN = [
'notifications', 'notifications',
]; ];
// TODO: close on scroll event too? // TODO: close on scroll event too?
export const closeAll = () => { export const closeAll = () => {
ags.App.windows.forEach(w => { App.windows.forEach(w => {
if (!ALWAYS_OPEN.some(window => window === w.name)) if (!ALWAYS_OPEN.some(window => window === w.name))
ags.App.closeWindow(w.name) closeWindow(w.name)
}); });
closeWindow('closer'); closeWindow('closer');
}; };
@ -24,8 +26,8 @@ export const Closer = Window({
child: EventBox({ child: EventBox({
onPrimaryClickRelease: () => closeAll(), onPrimaryClickRelease: () => closeAll(),
connections: [[ags.App, (_b, _w, _v) => { connections: [[App, (_b, _w, _v) => {
if (!Array.from(ags.App.windows).some(w => w[1].visible && if (!Array.from(App.windows).some(w => w[1].visible &&
!ALWAYS_OPEN.some(window => window === w[0]))) { !ALWAYS_OPEN.some(window => window === w[0]))) {
closeWindow('closer'); closeWindow('closer');
} }

View file

@ -1,7 +1,10 @@
import { Widget } from '../../imports.js';
import Gdk from 'gi://Gdk'; import Gdk from 'gi://Gdk';
const display = Gdk.Display.get_default(); const display = Gdk.Display.get_default();
export const EventBox = ({ reset = true, ...params }) => ags.Widget.EventBox({
export const EventBox = ({ reset = true, ...params }) => Widget.EventBox({
...params, ...params,
onHover: box => { onHover: box => {
if (! box.child.sensitive || ! box.sensitive) { if (! box.child.sensitive || ! box.sensitive) {
@ -17,7 +20,7 @@ export const EventBox = ({ reset = true, ...params }) => ags.Widget.EventBox({
}, },
}); });
export const Button = ({ reset = true, ...params }) => ags.Widget.Button({ export const Button = ({ reset = true, ...params }) => Widget.Button({
...params, ...params,
onHover: box => { onHover: box => {
if (! box.child.sensitive || ! box.sensitive) { if (! box.child.sensitive || ! box.sensitive) {

View file

@ -1,7 +1,11 @@
const { Box, EventBox } = ags.Widget; import { Widget } from '../../imports.js';
const { Gtk, Gdk } = imports.gi; const { Box, EventBox } = Widget;
import Gtk from 'gi://Gtk';
import Gdk from 'gi://Gdk';
const display = Gdk.Display.get_default(); const display = Gdk.Display.get_default();
export const Draggable = ({ export const Draggable = ({
maxOffset = 150, maxOffset = 150,
startMargin = 0, startMargin = 0,

View file

@ -1,5 +1,7 @@
const { Revealer, Box } = ags.Widget; import { App, Widget } from '../../imports.js';
const { openWindow } = ags.App; const { Revealer, Box } = Widget;
const { openWindow } = App;
export const PopUp = ({name, child, transition = 'slide_down', ...params}) => Box({ export const PopUp = ({name, child, transition = 'slide_down', ...params}) => Box({
style: 'min-height:1px; min-width:1px', style: 'min-height:1px; min-width:1px',
@ -7,7 +9,7 @@ export const PopUp = ({name, child, transition = 'slide_down', ...params}) => Bo
...params, ...params,
transition, transition,
transitionDuration: 500, transitionDuration: 500,
connections: [[ags.App, (revealer, currentName, visible) => { connections: [[App, (revealer, currentName, visible) => {
if (currentName === name) { if (currentName === name) {
revealer.reveal_child = visible; revealer.reveal_child = visible;

View file

@ -1,3 +1,7 @@
export const Separator = width => ags.Widget.Box({ import { Widget } from '../../imports.js';
const { Box } = Widget;
export const Separator = width => Box({
style: `min-width: ${width}px;`, style: `min-width: ${width}px;`,
}); });

View file

@ -1,17 +1,19 @@
const { GLib } = imports.gi; import { Applications, Utils, Widget } from '../../imports.js';
const { Notifications, Applications } = ags.Service; const { lookUpIcon, execAsync } = Utils;
const { lookUpIcon, exec, execAsync } = ags.Utils; const { Box, Icon, Label, Button } = Widget;
const { Box, Icon, Label, Button } = ags.Widget;
import GLib from 'gi://GLib';
import { Draggable } from '../misc/drag.js'; import { Draggable } from '../misc/drag.js';
import { EventBox } from '../misc/cursorbox.js' import { EventBox } from '../misc/cursorbox.js'
import { closeAll } from '../misc/closer.js'; import { closeAll } from '../misc/closer.js';
const NotificationIcon = ({ appEntry, appIcon, image }) => {
const NotificationIcon = notif => {
let iconCmd = () => {}; let iconCmd = () => {};
if (Applications.query(appEntry).length > 0) { if (Applications.query(notif.appEntry).length > 0) {
let app = Applications.query(appEntry)[0]; let app = Applications.query(notif.appEntry)[0];
if (app.app.get_string('StartupWMClass') != null) { if (app.app.get_string('StartupWMClass') != null) {
iconCmd = box => { iconCmd = box => {
@ -32,7 +34,7 @@ const NotificationIcon = ({ appEntry, appIcon, image }) => {
} }
} }
if (image) { if (notif.image) {
return EventBox({ return EventBox({
onPrimaryClickRelease: iconCmd, onPrimaryClickRelease: iconCmd,
child: Box({ child: Box({
@ -40,7 +42,7 @@ const NotificationIcon = ({ appEntry, appIcon, image }) => {
hexpand: false, hexpand: false,
className: 'icon img', className: 'icon img',
style: ` style: `
background-image: url("${image}"); background-image: url("${notif.image}");
background-size: contain; background-size: contain;
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center; background-position: center;
@ -52,12 +54,12 @@ const NotificationIcon = ({ appEntry, appIcon, image }) => {
} }
let icon = 'dialog-information-symbolic'; let icon = 'dialog-information-symbolic';
if (lookUpIcon(appIcon)) { if (lookUpIcon(notif.appIcon)) {
icon = appIcon; icon = notif.appIcon;
} }
if (lookUpIcon(appEntry)) { if (lookUpIcon(notif.appEntry)) {
icon = appEntry; icon = notif.appEntry;
} }
return EventBox({ return EventBox({
@ -81,22 +83,22 @@ const NotificationIcon = ({ appEntry, appIcon, image }) => {
}); });
}; };
export default ({ id, summary, body, actions, urgency, time, command = i => {}, ...icon }) => { export default ({ notif, command = () => {}} = {}) => {
const BlockedApps = [ const BlockedApps = [
'Spotify', 'Spotify',
]; ];
if (BlockedApps.find(app => app == Notifications.getNotification(id).appName)) { if (BlockedApps.find(app => app == notif.appName)) {
Notifications.close(id); notif.close();
return; return;
} }
return Draggable({ return Draggable({
maxOffset: 200, maxOffset: 200,
command: () => command(id), command: () => command(),
properties: [ properties: [
['hovered', false], ['hovered', false],
['id', id], ['id', notif.id],
], ],
onHover: w => { onHover: w => {
if (!w._hovered) { if (!w._hovered) {
@ -110,7 +112,7 @@ export default ({ id, summary, body, actions, urgency, time, command = i => {},
}, },
child: Box({ child: Box({
className: `notification ${urgency}`, className: `notification ${notif.urgency}`,
vexpand: false, vexpand: false,
// Notification // Notification
child: Box({ child: Box({
@ -119,7 +121,7 @@ export default ({ id, summary, body, actions, urgency, time, command = i => {},
// Content // Content
Box({ Box({
children: [ children: [
NotificationIcon(icon), NotificationIcon(notif),
Box({ Box({
hexpand: true, hexpand: true,
vertical: true, vertical: true,
@ -135,20 +137,20 @@ export default ({ id, summary, body, actions, urgency, time, command = i => {},
maxWidthChars: 24, maxWidthChars: 24,
truncate: 'end', truncate: 'end',
wrap: true, wrap: true,
label: summary, label: notif.summary,
useMarkup: summary.startsWith('<'), useMarkup: notif.summary.startsWith('<'),
}), }),
Label({ Label({
className: 'time', className: 'time',
valign: 'start', valign: 'start',
label: GLib.DateTime.new_from_unix_local(time).format('%H:%M'), label: GLib.DateTime.new_from_unix_local(notif.time).format('%H:%M'),
}), }),
EventBox({ EventBox({
reset: false, reset: false,
child: Button({ child: Button({
className: 'close-button', className: 'close-button',
valign: 'start', valign: 'start',
onClicked: () => Notifications.close(id), onClicked: () => notif.close(),
child: Icon('window-close-symbolic'), child: Icon('window-close-symbolic'),
}), }),
}), }),
@ -160,7 +162,7 @@ export default ({ id, summary, body, actions, urgency, time, command = i => {},
useMarkup: true, useMarkup: true,
xalign: 0, xalign: 0,
justification: 'left', justification: 'left',
label: body, label: notif.body,
wrap: true, wrap: true,
}), }),
], ],
@ -170,9 +172,9 @@ export default ({ id, summary, body, actions, urgency, time, command = i => {},
// Actions // Actions
Box({ Box({
className: 'actions', className: 'actions',
children: actions.map(action => Button({ children: notif.actions.map(action => Button({
className: 'action-button', className: 'action-button',
onClicked: () => Notifications.invoke(id, action.id), onClicked: () => notif.invoke(action.id),
hexpand: true, hexpand: true,
child: Label(action.label), child: Label(action.label),
})), })),

View file

@ -1,12 +1,13 @@
const { Notifications } = ags.Service; import { Notifications, App, Utils, Widget } from '../../imports.js';
const { Button, Label, Box, Icon, Scrollable, Window, Revealer } = ags.Widget; const { Button, Label, Box, Icon, Scrollable, Window, Revealer } = Widget;
const { timeout } = ags.Utils; const { timeout } = Utils;
const { getWindow } = ags.App; const { getWindow } = App;
import Notification from './base.js'; import Notification from './base.js';
import { EventBox } from '../misc/cursorbox.js'; import { EventBox } from '../misc/cursorbox.js';
import { PopUp } from '../misc/popup.js'; import { PopUp } from '../misc/popup.js';
const ClearButton = () => EventBox({ const ClearButton = () => EventBox({
child: Button({ child: Button({
onPrimaryClickRelease: button => { onPrimaryClickRelease: button => {
@ -59,12 +60,14 @@ const NotificationList = Box({
if (box.children.length == 0) { if (box.children.length == 0) {
box.children = Notifications.notifications box.children = Notifications.notifications
.reverse() .reverse()
.map(n => Notification({ ...n, command: i => Notifications.close(i), })); .map(n => Notification({ notif: n, command: () => n.close() }));
} }
else if (id) { else if (id) {
let notif = Notifications.getNotification(id);
const NewNotif = Notification({ const NewNotif = Notification({
...Notifications.getNotification(id), notif,
command: i => Notifications.close(i), command: () => notif.close(),
}); });
if (NewNotif) { if (NewNotif) {

View file

@ -1,8 +1,12 @@
import { Notifications, Utils, Widget } from '../../imports.js';
const { Box, Revealer, Window } = Widget;
const { timeout, interval } = Utils;
import GLib from 'gi://GLib';
const { source_remove } = GLib;
import Notification from './base.js'; import Notification from './base.js';
const { Notifications } = ags.Service;
const { Box, Revealer, Window } = ags.Widget;
const { timeout, interval } = ags.Utils;
const { source_remove } = imports.gi.GLib;
const Popups = () => Box({ const Popups = () => Box({
vertical: true, vertical: true,
@ -36,9 +40,10 @@ const Popups = () => Box({
box._map.delete(id); box._map.delete(id);
let notif = Notifications.getNotification(id);
box._map.set(id, Notification({ box._map.set(id, Notification({
...Notifications.getNotification(id), notif,
command: i => Notifications.dismiss(i), command: () => notif.dismiss(),
})); }));
box.children = Array.from(box._map.values()).reverse(); box.children = Array.from(box._map.values()).reverse();

View file

@ -1,17 +1,19 @@
const { Icon, Revealer } = ags.Widget; import { App, Hyprland, Utils, Widget } from '../../imports.js';
const { closeWindow } = ags.App; const { Icon, Revealer } = Widget;
const { execAsync } = ags.Utils; const { closeWindow } = App;
const { Hyprland } = ags.Service; const { execAsync } = Utils;
import { WindowButton } from './dragndrop.js'; import { WindowButton } from './dragndrop.js';
import * as VARS from './variables.js'; import * as VARS from './variables.js';
Array.prototype.remove = function (el) { this.splice(this.indexOf(el), 1) }; Array.prototype.remove = function (el) { this.splice(this.indexOf(el), 1) };
const IconStyle = app => `min-width: ${app.size[0] * VARS.SCALE - VARS.MARGIN}px; const IconStyle = app => `min-width: ${app.size[0] * VARS.SCALE - VARS.MARGIN}px;
min-height: ${app.size[1] * 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, font-size: ${Math.min(app.size[0] * VARS.SCALE - VARS.MARGIN,
app.size[1] * VARS.SCALE - VARS.MARGIN) * VARS.ICON_SCALE}px;`; app.size[1] * VARS.SCALE - VARS.MARGIN) * VARS.ICON_SCALE}px;`;
const Client = (client, active, clients) => Revealer({ const Client = (client, active, clients) => Revealer({
transition: 'crossfade', transition: 'crossfade',
setup: rev => { setup: rev => {
@ -65,7 +67,7 @@ const Client = (client, active, clients) => Revealer({
}); });
export function updateClients(box) { export function updateClients(box) {
ags.Utils.execAsync('hyprctl clients -j') execAsync('hyprctl clients -j')
.then(result => { .then(result => {
let clients = JSON.parse(result).filter(client => client.class) let clients = JSON.parse(result).filter(client => client.class)

View file

@ -1,14 +1,17 @@
const { Gtk, Gdk } = imports.gi; import { App, Utils, Widget } from '../../imports.js';
const { EventBox } = ags.Widget; const { EventBox } = Widget;
const { execAsync } = ags.Utils; const { execAsync } = Utils;
const { getWindow } = ags.App; const { getWindow } = App;
import Gtk from 'gi://Gtk';
import Gdk from 'gi://Gdk';
import Cairo from 'cairo'; import Cairo from 'cairo';
import { Button } from '../misc/cursorbox.js'; import { Button } from '../misc/cursorbox.js';
const TARGET = [Gtk.TargetEntry.new('text/plain', Gtk.TargetFlags.SAME_APP, 0)]; const TARGET = [Gtk.TargetEntry.new('text/plain', Gtk.TargetFlags.SAME_APP, 0)];
function createSurfaceFromWidget(widget) { function createSurfaceFromWidget(widget) {
const alloc = widget.get_allocation(); const alloc = widget.get_allocation();
const surface = new Cairo.ImageSurface( const surface = new Cairo.ImageSurface(
@ -28,7 +31,6 @@ function createSurfaceFromWidget(widget) {
let hidden = 0; let hidden = 0;
export const WorkspaceDrop = params => EventBox({ export const WorkspaceDrop = params => EventBox({
...params, ...params,
//tooltipText: `Workspace: ${id}`,
connections: [['drag-data-received', (eventbox, _c, _x, _y, data) => { connections: [['drag-data-received', (eventbox, _c, _x, _y, data) => {
let id = eventbox.get_parent()._id; let id = eventbox.get_parent()._id;

View file

@ -1,10 +1,11 @@
const { Window, Box } = ags.Widget; import { Hyprland, Widget } from '../../imports.js';
const { Hyprland } = ags.Service; const { Window, Box } = Widget;
import { PopUp } from '../misc/popup.js'; import { PopUp } from '../misc/popup.js';
import { WorkspaceRow, getWorkspaces, updateWorkspaces } from './workspaces.js'; import { WorkspaceRow, getWorkspaces, updateWorkspaces } from './workspaces.js';
import { updateClients } from './clients.js'; import { updateClients } from './clients.js';
export default Window({ export default Window({
name: 'overview', name: 'overview',
layer: 'overlay', layer: 'overlay',

View file

@ -1,6 +1,7 @@
const { Revealer, CenterBox, Box, EventBox, Label, Overlay } = ags.Widget; import { Hyprland, Widget } from '../../imports.js';
const { Hyprland } = ags.Service; const { Revealer, CenterBox, Box, EventBox, Label, Overlay } = Widget;
const { Gtk } = imports.gi;
import Gtk from 'gi://Gtk';
import { WorkspaceDrop } from './dragndrop.js'; import { WorkspaceDrop } from './dragndrop.js';
import * as VARS from './variables.js'; import * as VARS from './variables.js';
@ -8,6 +9,7 @@ import * as VARS from './variables.js';
const DEFAULT_STYLE = `min-width: ${VARS.SCREEN.X * VARS.SCALE}px; const DEFAULT_STYLE = `min-width: ${VARS.SCREEN.X * VARS.SCALE}px;
min-height: ${VARS.SCREEN.Y * VARS.SCALE}px;`; min-height: ${VARS.SCREEN.Y * VARS.SCALE}px;`;
export function getWorkspaces(box) { export function getWorkspaces(box) {
let children = []; let children = [];
box.children.forEach(type => { box.children.forEach(type => {
@ -61,7 +63,7 @@ export const WorkspaceRow = (className, i) => Revealer({
overlays: [Box({ overlays: [Box({
style: DEFAULT_STYLE, style: DEFAULT_STYLE,
children: [ children: [
ags.Widget({ Widget({
type: Gtk.Fixed, type: Gtk.Fixed,
}), }),
Label({ Label({
@ -89,7 +91,7 @@ const Workspace = (id, name) => Revealer({
['wasActive', false], ['wasActive', false],
], ],
connections: [[Hyprland, box => { connections: [[Hyprland, box => {
box._timeouts.forEach(clearTimeout); box._timeouts.forEach(timer => timer.destroy());
let activeId = Hyprland.active.workspace.id; let activeId = Hyprland.active.workspace.id;
let active = activeId === box._id; let active = activeId === box._id;
@ -119,12 +121,12 @@ const Workspace = (id, name) => Revealer({
box._wasActive = true; box._wasActive = true;
} }
else if (box._wasActive) { else if (box._wasActive) {
box._wasActive = false;
box._timeouts.push(setTimeout(() => { box._timeouts.push(setTimeout(() => {
rev.setStyle(`${DEFAULT_STYLE} rev.setStyle(`${DEFAULT_STYLE}
transition: margin 0.5s ease-in-out; transition: margin 0.5s ease-in-out;
opacity: 1; margin-left: ${n ? '' : '-'}300px; opacity: 1; margin-left: ${n ? '' : '-'}300px;
margin-right: ${n ? '-' : ''}300px;`); margin-right: ${n ? '-' : ''}300px;`);
box._wasActive = false;
}, 120)); }, 120));
box._timeouts.push(setTimeout(() => { box._timeouts.push(setTimeout(() => {
rev.setStyle(`${DEFAULT_STYLE} opacity: 0; rev.setStyle(`${DEFAULT_STYLE} opacity: 0;
@ -147,7 +149,7 @@ const Workspace = (id, name) => Revealer({
overlays: [Box({ overlays: [Box({
className: 'workspace', className: 'workspace',
style: DEFAULT_STYLE, style: DEFAULT_STYLE,
child: ags.Widget({ child: Widget({
type: Gtk.Fixed, type: Gtk.Fixed,
}), }),
})], })],

View file

@ -1,8 +1,10 @@
const { Window, CenterBox, Label } = ags.Widget; import { Widget } from '../imports.js';
const { Window, CenterBox, Label } = Widget;
import { PopUp } from './misc/popup.js'; import { PopUp } from './misc/popup.js';
import { Button } from './misc/cursorbox.js' import { Button } from './misc/cursorbox.js'
const PowermenuWidget = CenterBox({ const PowermenuWidget = CenterBox({
className: 'powermenu', className: 'powermenu',
vertical: false, vertical: false,

View file

@ -1,10 +1,11 @@
const { Box, CenterBox, Label, Icon } = ags.Widget; import { Network, Bluetooth, Audio, App, Utils, Widget } from '../../imports.js';
const { Network, Bluetooth, Audio } = ags.Service; const { Box, CenterBox, Label, Icon } = Widget;
const { execAsync } = ags.Utils; const { execAsync } = Utils;
const { openWindow } = ags.App; const { openWindow } = App;
import { EventBox } from '../misc/cursorbox.js'; import { EventBox } from '../misc/cursorbox.js';
const GridButton = ({ command = () => {}, secondaryCommand = () => {}, icon } = {}) => Box({ const GridButton = ({ command = () => {}, secondaryCommand = () => {}, icon } = {}) => Box({
className: 'grid-button', className: 'grid-button',
children: [ children: [
@ -148,7 +149,7 @@ const SecondRow = Box({
className: 'grid-label', className: 'grid-label',
connections: [[Audio, icon => { connections: [[Audio, icon => {
if (Audio.speaker) { if (Audio.speaker) {
if (Audio.speaker.isMuted) { if (Audio.speaker.stream.isMuted) {
icon.icon = items[0]; icon.icon = items[0];
} }
else { else {
@ -171,7 +172,7 @@ const SecondRow = Box({
className: 'grid-label', className: 'grid-label',
connections: [[Audio, icon => { connections: [[Audio, icon => {
if (Audio.microphone) { if (Audio.microphone) {
if (Audio.microphone.isMuted) { if (Audio.microphone.stream.isMuted) {
icon.icon = itemsMic[0]; icon.icon = itemsMic[0];
} }
else { else {

View file

@ -1,6 +1,7 @@
const { Window, Box, Label, Revealer, Icon } = ags.Widget; import { Mpris, Widget } from '../../imports.js';
const { Mpris } = ags.Service; const { Window, Box, Label, Revealer, Icon } = Widget;
const { ToggleButton } = imports.gi.Gtk;
import Gtk from 'gi://Gtk';
import { ButtonGrid } from './button-grid.js'; import { ButtonGrid } from './button-grid.js';
import { SliderBox } from './slider-box.js'; import { SliderBox } from './slider-box.js';
@ -8,6 +9,7 @@ import Player from '../media-player/player.js';
import { EventBox } from '../misc/cursorbox.js'; import { EventBox } from '../misc/cursorbox.js';
import { PopUp } from '../misc/popup.js'; import { PopUp } from '../misc/popup.js';
const QuickSettingsWidget = Box({ const QuickSettingsWidget = Box({
className: 'qs-container', className: 'qs-container',
vertical: true, vertical: true,
@ -30,12 +32,12 @@ const QuickSettingsWidget = Box({
SliderBox, SliderBox,
EventBox({ EventBox({
child: ags.Widget({ child: Widget({
type: ToggleButton, type: Gtk.ToggleButton,
setup: btn => { setup: btn => {
const id = Mpris.instance.connect('changed', () => { const id = Mpris.connect('changed', () => {
btn.set_active(Mpris.players.length > 0); btn.set_active(Mpris.players.length > 0);
Mpris.instance.disconnect(id); Mpris.disconnect(id);
}); });
}, },
connections: [['toggled', button => { connections: [['toggled', button => {

View file

@ -1,6 +1,6 @@
const { Box, Slider, Icon, EventBox } = ags.Widget; import { Audio, Utils, Widget } from '../../imports.js';
const { Audio } = ags.Service; const { Box, Slider, Icon, EventBox } = Widget;
const { execAsync } = ags.Utils; const { execAsync } = Utils;
const items = { const items = {
101: 'audio-volume-overamplified-symbolic', 101: 'audio-volume-overamplified-symbolic',
@ -10,6 +10,7 @@ const items = {
0: 'audio-volume-muted-symbolic', 0: 'audio-volume-muted-symbolic',
}; };
export const SliderBox = Box({ export const SliderBox = Box({
className: 'slider-box', className: 'slider-box',
vertical: true, vertical: true,
@ -26,7 +27,7 @@ export const SliderBox = Box({
className: 'slider-label', className: 'slider-label',
connections: [[Audio, icon => { connections: [[Audio, icon => {
if (Audio.speaker) { if (Audio.speaker) {
if (Audio.speaker.isMuted) { if (Audio.speaker.stream.isMuted) {
icon.icon = items[0]; icon.icon = items[0];
} }
else { else {

View file

@ -12,8 +12,7 @@ Libinput.instance.connect('device-init', () => {
}); });
*/ */
const { Service } = ags; const { Service, Utils } = '../imports.js';
const { execAsync } = ags.Utils;
import GLib from 'gi://GLib'; import GLib from 'gi://GLib';
import Gio from 'gi://Gio'; import Gio from 'gi://Gio';
import GObject from 'gi://GObject'; import GObject from 'gi://GObject';
@ -123,7 +122,7 @@ class LibinputService extends Service {
constructor() { constructor() {
super(); super();
this.debugInstances = new Map(); this.debugInstances = new Map();
execAsync(['libinput', 'list-devices']) Utils.execAsync(['libinput', 'list-devices'])
.then(out => this.parseOutput(out)) .then(out => this.parseOutput(out))
.catch(console.error); .catch(console.error);
} }

View file

@ -171,7 +171,7 @@ bind = $mainMod, C, killactive,
bind = $mainMod, L, exec, $LOCK_PATH/lock.sh bind = $mainMod, L, exec, $LOCK_PATH/lock.sh
bind = $mainMod SHIFT, E, exec, ags run-js 'ags.App.openWindow("powermenu")' bind = $mainMod SHIFT, E, exec, ags run-js 'ags.App.openWindow("powermenu")'
bindn =, Escape, exec, ags run-js 'ags.App.closeAll()' bindn =, Escape, exec, ags run-js 'closeAll()'
bind = $mainMod SHIFT, SPACE, togglefloating, bind = $mainMod SHIFT, SPACE, togglefloating,
bind = $mainMod, D, exec, ags -t applauncher bind = $mainMod, D, exec, ags -t applauncher
bind = $mainMod, P, pseudo, # dwindle bind = $mainMod, P, pseudo, # dwindle

Binary file not shown.