[Astal] Finish modes, move tray into quickactions menu

This commit is contained in:
2025-10-17 10:43:50 +02:00
parent 00d4f101fc
commit 539ec34b4c
6 changed files with 175 additions and 108 deletions

View File

@@ -1,44 +1,58 @@
import { Gtk } from "astal/gtk4"; import Audio from './modules/Audio/Audio';
import Power from "./modules/Power"; import {
import Audio from "./modules/Audio/Audio"; BatteryBox
import Bluetooth from "./modules/Bluetooth/Bluetooth"; } from './modules/Battery';
import Brightness from "./modules/Brightness/Brightness"; import Bluetooth from './modules/Bluetooth/Bluetooth';
import Player from "./modules/Player/Player"; import Brightness from './modules/Brightness/Brightness';
import { BatteryBox } from "./modules/Battery"; import {
import { exec } from "astal"; Gtk
import Network from "./modules/Networking/Network"; } from 'astal/gtk4';
import Network from './modules/Networking/Network';
import Player from './modules/Player/Player';
import Power from './modules/Power';
import SysTray from './modules/SysTray';
import {
exec
} from 'astal';
const QuickActions = () => { const QuickActions = () => {
const popover = new Gtk.Popover({ cssClasses: ["quick-actions-wrapper"] }); const popover = new Gtk.Popover( {
popover.set_child(renderQuickActions()); 'cssClasses': [ 'quick-actions-wrapper' ]
} );
popover.set_child( renderQuickActions() );
return popover; return popover;
}; };
const renderQuickActions = () => { const renderQuickActions = () => {
const user = exec("/bin/sh -c whoami"); const user = exec( '/bin/sh -c whoami' );
const profile = exec("/bin/fish -c get-profile-picture"); const profile = exec( '/bin/fish -c get-profile-picture' );
const cwd = exec("pwd"); const cwd = exec( 'pwd' );
const um = Power.UserMenu(); const um = Power.UserMenu();
return ( return (
<box visible cssClasses={["quick-actions", "popover-box"]} vertical> <box visible cssClasses={[
'quick-actions',
'popover-box'
]} vertical>
<centerbox <centerbox
startWidget={ startWidget={
<button <button
onClicked={() => um.popup()} onClicked={() => um.popup()}
cssClasses={["stealthy-button"]} cssClasses={[ 'stealthy-button' ]}
child={ child={
<box> <box>
{um} {um}
<Gtk.Frame <Gtk.Frame
cssClasses={["avatar-icon"]} cssClasses={[ 'avatar-icon' ]}
child={ child={
<image <image
file={ file={
profile !== "" profile !== ''
? profile ? profile
: cwd + : cwd
"/no-avatar-icon.jpg" + '/no-avatar-icon.jpg'
} }
></image> ></image>
} }
@@ -53,6 +67,7 @@ const renderQuickActions = () => {
hexpand={false} hexpand={false}
> >
<BatteryBox></BatteryBox> <BatteryBox></BatteryBox>
<SysTray.SystemTray></SysTray.SystemTray>
<Power.Power></Power.Power> <Power.Power></Power.Power>
</box> </box>
} }

View File

@@ -1,48 +1,56 @@
import { exec } from "astal"; import {
import { Gtk } from "astal/gtk4"; exec
} from 'astal';
import {
Gtk
} from 'astal/gtk4';
const PowerMenu = (): Gtk.Popover => { const PowerMenu = (): Gtk.Popover => {
const popover = new Gtk.Popover({ cssClasses: ["PowerMenu"] }); const popover = new Gtk.Popover( {
'cssClasses': [ 'PowerMenu' ]
} );
const powerMenuBox = () => { const powerMenuBox = () => {
return ( return (
<box> <box>
<button <button
cssClasses={["power-button"]} cssClasses={[ 'power-button' ]}
child={ child={
<image iconName={"system-shutdown-symbolic"}></image> <image iconName={'system-shutdown-symbolic'}></image>
} }
onClicked={() => exec("/bin/sh -c 'shutdown now'")} onClicked={() => exec( '/bin/sh -c \'shutdown now\'' )}
></button> ></button>
<button <button
cssClasses={["power-button"]} cssClasses={[ 'power-button' ]}
child={<image iconName={"system-reboot-symbolic"}></image>} child={<image iconName={'system-reboot-symbolic'}></image>}
onClicked={() => exec("/bin/sh -c 'reboot'")} onClicked={() => exec( '/bin/sh -c \'reboot\'' )}
></button> ></button>
<button <button
cssClasses={["power-button"]} cssClasses={[ 'power-button' ]}
child={<image iconName={"system-suspend-symbolic"}></image>} child={<image iconName={'system-suspend-symbolic'}></image>}
onClicked={() => exec("/bin/sh -c 'systemctl suspend'")} onClicked={() => exec( '/bin/sh -c \'systemctl suspend\'' )}
></button> ></button>
</box> </box>
); );
}; };
popover.set_child(powerMenuBox()); popover.set_child( powerMenuBox() );
return popover; return popover;
}; };
const Power = () => { const Power = () => {
const pm = PowerMenu(); const pm = PowerMenu();
return ( return (
<button <button
widthRequest={0} widthRequest={0}
hexpand={false} hexpand={false}
vexpand={false} vexpand={false}
cssClasses={["power-menu-button"]} cssClasses={[ 'power-menu-button' ]}
child={ child={
<box> <box>
<image iconName={"system-shutdown-symbolic"}></image> <image iconName={'system-shutdown-symbolic'}></image>
{pm} {pm}
</box> </box>
} }
@@ -58,24 +66,24 @@ const UserMenu = (): Gtk.Popover => {
return ( return (
<box> <box>
<button <button
cssClasses={["power-button"]} cssClasses={[ 'power-button' ]}
child={ child={
<image iconName={"system-lock-screen-symbolic"}></image> <image iconName={'system-lock-screen-symbolic'}></image>
} }
onClicked={() => exec("/bin/sh -c 'hyprlock'")} onClicked={() => exec( '/bin/sh -c \'hyprlock\'' )}
></button> ></button>
<button <button
cssClasses={["power-button"]} cssClasses={[ 'power-button' ]}
child={<image iconName={"system-log-out-symbolic"}></image>} child={<image iconName={'system-log-out-symbolic'}></image>}
onClicked={() => onClicked={() => exec( '/bin/sh -c \'hyprctl dispatch exit 0\'' )
exec("/bin/sh -c 'hyprctl dispatch exit 0'")
} }
></button> ></button>
</box> </box>
); );
}; };
popover.set_child(powerMenuBox()); popover.set_child( powerMenuBox() );
return popover; return popover;
}; };

View File

@@ -0,0 +1,88 @@
import AstalTray from 'gi://AstalTray';
import {
GObject
} from 'astal';
import {
Gtk
} from 'astal/gtk4';
const SYNC = GObject.BindingFlags.SYNC_CREATE;
const SysTray = () => {
const trayBox = new Gtk.Box( {
'cssClasses': [ '' ]
} );
const tray = AstalTray.get_default();
const trayItems = new Map<string, Gtk.MenuButton>();
const trayAddedHandler = tray.connect( 'item-added', ( _, id ) => {
const item = tray.get_item( id );
const popover = Gtk.PopoverMenu.new_from_model( item.menu_model );
const icon = new Gtk.Image();
const button = new Gtk.MenuButton( {
popover,
'child': icon,
'cssClasses': [ 'tray-item' ],
} );
item.bind_property(
'gicon', icon, 'gicon', SYNC
);
popover.insert_action_group( 'dbusmenu', item.action_group );
item.connect( 'notify::action-group', () => {
popover.insert_action_group( 'dbusmenu', item.action_group );
} );
trayItems.set( id, button );
trayBox.append( button );
} );
const trayRemovedHandler = tray.connect( 'item-removed', ( _, id ) => {
const button = trayItems.get( id );
if ( button ) {
trayBox.remove( button );
button.run_dispose();
trayItems.delete( id );
}
} );
trayBox.connect( 'destroy', () => {
tray.disconnect( trayAddedHandler );
tray.disconnect( trayRemovedHandler );
} );
return trayBox;
};
const TrayPopover = () => {
const popover = new Gtk.Popover( {
'cssClasses': [ 'TrayPopover' ]
} );
popover.set_child( SysTray() );
return popover;
};
const SystemTray = () => {
const systray = TrayPopover();
return (
<button
widthRequest={0}
hexpand={false}
vexpand={false}
cssClasses={[ 'power-menu-button' ]}
child={
<box>
<image iconName={'systemtray'}></image>
{systray}
</box>
}
onClicked={() => systray.popup()}
/>
);
};
export default {
SystemTray
};

View File

@@ -39,7 +39,6 @@ const Bar = ( {
> >
<Hyprland.ModeStatus /> <Hyprland.ModeStatus />
<Calendar.Time /> <Calendar.Time />
<SystemInfo.SystemInfo />
<Hyprland.Workspace /> <Hyprland.Workspace />
</box> </box>
} }
@@ -50,7 +49,7 @@ const Bar = ( {
halign={Gtk.Align.END} halign={Gtk.Align.END}
cssClasses={[ 'BarRight' ]} cssClasses={[ 'BarRight' ]}
> >
<Hyprland.SysTray /> <SystemInfo.SystemInfo />
<QuickView.QuickView /> <QuickView.QuickView />
</box> </box>
} }

View File

@@ -20,6 +20,11 @@ window.Bar {
border-radius: 20px; border-radius: 20px;
font-family: $monospace-font; font-family: $monospace-font;
&.command-mode {
background-color: darkslategray;
color: white;
}
&.windowing-mode { &.windowing-mode {
background-color: darkslategray; background-color: darkslategray;
color: white; color: white;

View File

@@ -1,62 +1,15 @@
import { import {
GObject, bind, bind,
exec, exec,
readFile readFile
} from 'astal'; } from 'astal';
import AstalHyprland from 'gi://AstalHyprland'; import AstalHyprland from 'gi://AstalHyprland';
import AstalTray from 'gi://AstalTray';
import { import {
Gtk Gtk
} from 'astal/gtk4'; } from 'astal/gtk4';
import Pango from 'gi://Pango?version=1.0'; import Pango from 'gi://Pango?version=1.0';
const hypr = AstalHyprland.get_default(); const hypr = AstalHyprland.get_default();
const SYNC = GObject.BindingFlags.SYNC_CREATE;
const SysTray = () => {
const trayBox = new Gtk.Box( {
'cssClasses': [ 'bar-button' ]
} );
const tray = AstalTray.get_default();
const trayItems = new Map<string, Gtk.MenuButton>();
const trayAddedHandler = tray.connect( 'item-added', ( _, id ) => {
const item = tray.get_item( id );
const popover = Gtk.PopoverMenu.new_from_model( item.menu_model );
const icon = new Gtk.Image();
const button = new Gtk.MenuButton( {
popover,
'child': icon,
'cssClasses': [ 'tray-item' ],
} );
item.bind_property(
'gicon', icon, 'gicon', SYNC
);
popover.insert_action_group( 'dbusmenu', item.action_group );
item.connect( 'notify::action-group', () => {
popover.insert_action_group( 'dbusmenu', item.action_group );
} );
trayItems.set( id, button );
trayBox.append( button );
} );
const trayRemovedHandler = tray.connect( 'item-removed', ( _, id ) => {
const button = trayItems.get( id );
if ( button ) {
trayBox.remove( button );
button.run_dispose();
trayItems.delete( id );
}
} );
trayBox.connect( 'destroy', () => {
tray.disconnect( trayAddedHandler );
tray.disconnect( trayRemovedHandler );
} );
return trayBox;
};
const Workspace = () => { const Workspace = () => {
return ( return (
@@ -123,33 +76,33 @@ const ActiveWindow = () => {
type submaps = 'device' | 'launch' | 'workspace' | 'windowing' | 'screenshotting' | 'notifications' | ''; type submaps = 'device' | 'launch' | 'workspace' | 'windowing' | 'screenshotting' | 'notifications' | '';
const ModeStatus = () => { const ModeStatus = () => {
let isUsingHyprmode = false; let isUsingHyprvim = false;
try { try {
const path = exec( 'bash -c "cd ~ && pwd"' ) + '/.config/hyprmode'; const path = exec( 'bash -c "cd ~ && pwd"' ) + '/.config/hyprvim';
isUsingHyprmode = readFile( path ).trim() === 'y'; isUsingHyprvim = readFile( path ).trim() === 'y';
} catch ( e ) { } catch ( e ) {
printerr( 'Failed to read hyprmode config', e ); printerr( 'Failed to read hyprvim config', e );
} }
const label = new Gtk.Label(); const label = new Gtk.Label();
if ( !isUsingHyprmode ) return label; if ( !isUsingHyprvim ) return label;
print( '==> Using hyprmode config' ); print( '==> Using hyprvim config' );
const map = { const map = {
'device': 'D', 'device': 'DEV',
'launch': 'L', 'launch': 'LNC',
'workspace': 'W', 'workspace': 'WSP',
'windowing': 'M', 'windowing': 'WIN',
'screenshotting': 'S', 'screenshotting': 'SCS',
'notifications': 'N', 'notifications': 'NOT',
'': 'N' '': 'NRM'
}; };
label.label = 'N'; label.label = map[''];
label.cssClasses = [ 'mode-status' ]; label.cssClasses = [ 'mode-status' ];
// TODO: Possibly add popover to it that lists binds // TODO: Possibly add popover to it that lists binds
@@ -189,6 +142,5 @@ const WindowPopoverBox = () => {
export default { export default {
Workspace, Workspace,
ActiveWindow, ActiveWindow,
SysTray,
ModeStatus ModeStatus
}; };