OSDs are now click through and can have borders. (#674)
This commit is contained in:
@@ -551,6 +551,7 @@ in
|
|||||||
theme.osd.opacity = mkIntOption 100;
|
theme.osd.opacity = mkIntOption 100;
|
||||||
theme.osd.orientation = mkStrOption "vertical";
|
theme.osd.orientation = mkStrOption "vertical";
|
||||||
theme.osd.radius = mkStrOption "0.4em";
|
theme.osd.radius = mkStrOption "0.4em";
|
||||||
|
theme.osd.border.size = mkStrOption "0em";
|
||||||
theme.osd.scaling = mkIntOption 100;
|
theme.osd.scaling = mkIntOption 100;
|
||||||
theme.tooltip.scaling = mkIntOption 100;
|
theme.tooltip.scaling = mkIntOption 100;
|
||||||
wallpaper.enable = mkBoolOption true;
|
wallpaper.enable = mkBoolOption true;
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { Binding } from 'astal';
|
|
||||||
import { bind, timeout, Variable } from 'astal';
|
import { bind, timeout, Variable } from 'astal';
|
||||||
import { Widget } from 'astal/gtk3';
|
import { Widget } from 'astal/gtk3';
|
||||||
import { audioService, brightnessService, hyprlandService } from 'src/lib/constants/services';
|
import { audioService, brightnessService, hyprlandService } from 'src/lib/constants/services';
|
||||||
@@ -17,16 +16,19 @@ timeout(3000, () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the reveal state of a Widget.Revealer.
|
* Handles the reveal state of a Widget.Revealer or Widget.Window.
|
||||||
*
|
*
|
||||||
* This function sets the `reveal_child` property of the Widget.Revealer to true if the OSD is enabled and the property is 'revealChild'.
|
* This function delegates the reveal handling to either `handleRevealRevealer` or `handleRevealWindow` based on the type of the widget.
|
||||||
* It also manages a timeout to reset the `reveal_child` property after the specified duration.
|
|
||||||
*
|
*
|
||||||
* @param self The Widget.Revealer instance.
|
* @param self The Widget.Revealer or Widget.Window instance.
|
||||||
* @param property The property to check, either 'revealChild' or 'visible'.
|
* @param property The property to check, either 'revealChild' or 'visible'.
|
||||||
*/
|
*/
|
||||||
export const handleRevealRevealer = (self: Widget.Revealer, property: 'revealChild' | 'visible'): void => {
|
export const handleReveal = (self: Widget.Revealer): void => {
|
||||||
if (!enable.get() || property !== 'revealChild') {
|
if (isStartingUp) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enable.get()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,60 +44,14 @@ export const handleRevealRevealer = (self: Widget.Revealer, property: 'revealChi
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the reveal state of a Widget.Window.
|
|
||||||
*
|
|
||||||
* This function sets the `visible` property of the Widget.Window to true if the OSD is enabled and the property is 'visible'.
|
|
||||||
* It also manages a timeout to reset the `visible` property after the specified duration.
|
|
||||||
*
|
|
||||||
* @param self The Widget.Window instance.
|
|
||||||
* @param property The property to check, either 'revealChild' or 'visible'.
|
|
||||||
*/
|
|
||||||
export const handleRevealWindow = (self: Widget.Window, property: 'revealChild' | 'visible'): void => {
|
|
||||||
if (!enable.get() || property !== 'visible') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.visible = true;
|
|
||||||
|
|
||||||
count++;
|
|
||||||
timeout(duration.get(), () => {
|
|
||||||
count--;
|
|
||||||
|
|
||||||
if (count === 0) {
|
|
||||||
self.visible = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the reveal state of a Widget.Revealer or Widget.Window.
|
|
||||||
*
|
|
||||||
* This function delegates the reveal handling to either `handleRevealRevealer` or `handleRevealWindow` based on the type of the widget.
|
|
||||||
*
|
|
||||||
* @param self The Widget.Revealer or Widget.Window instance.
|
|
||||||
* @param property The property to check, either 'revealChild' or 'visible'.
|
|
||||||
*/
|
|
||||||
export const handleReveal = (self: Widget.Revealer | Widget.Window, property: 'revealChild' | 'visible'): void => {
|
|
||||||
if (isStartingUp) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self instanceof Widget.Revealer) {
|
|
||||||
handleRevealRevealer(self, property);
|
|
||||||
} else if (self instanceof Widget.Window) {
|
|
||||||
handleRevealWindow(self, property);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the monitor index for the OSD.
|
* Retrieves the monitor index for the OSD.
|
||||||
*
|
*
|
||||||
* This function derives the monitor index for the OSD based on the focused monitor, default monitor, and active monitor settings.
|
* This function derives the monitor index for the OSD based on the focused monitor, default monitor, and active monitor settings.
|
||||||
*
|
*
|
||||||
* @returns A Binding<number> representing the monitor index for the OSD.
|
* @returns A Variable<number> representing the monitor index for the OSD.
|
||||||
*/
|
*/
|
||||||
export const getOsdMonitor = (): Binding<number> => {
|
export const getOsdMonitor = (): Variable<number> => {
|
||||||
return Variable.derive(
|
return Variable.derive(
|
||||||
[bind(hyprlandService, 'focusedMonitor'), bind(monitor), bind(active_monitor)],
|
[bind(hyprlandService, 'focusedMonitor'), bind(monitor), bind(active_monitor)],
|
||||||
(currentMonitor, defaultMonitor, followMonitor) => {
|
(currentMonitor, defaultMonitor, followMonitor) => {
|
||||||
@@ -105,39 +61,7 @@ export const getOsdMonitor = (): Binding<number> => {
|
|||||||
|
|
||||||
return defaultMonitor;
|
return defaultMonitor;
|
||||||
},
|
},
|
||||||
)();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets up the window for OSD.
|
|
||||||
*
|
|
||||||
* This function hooks various services and settings to the window to handle its visibility based on the OSD configuration.
|
|
||||||
*
|
|
||||||
* @param self The Widget.Window instance to set up.
|
|
||||||
*/
|
|
||||||
export const windowSetup = (self: Widget.Window): void => {
|
|
||||||
self.hook(enable, () => {
|
|
||||||
handleReveal(self, 'visible');
|
|
||||||
});
|
|
||||||
|
|
||||||
self.hook(brightnessService, 'notify::screen', () => {
|
|
||||||
handleReveal(self, 'visible');
|
|
||||||
});
|
|
||||||
|
|
||||||
self.hook(brightnessService, 'notify::kbd', () => {
|
|
||||||
handleReveal(self, 'visible');
|
|
||||||
});
|
|
||||||
|
|
||||||
Variable.derive(
|
|
||||||
[bind(audioService.defaultMicrophone, 'volume'), bind(audioService.defaultMicrophone, 'mute')],
|
|
||||||
() => {
|
|
||||||
handleReveal(self, 'visible');
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Variable.derive([bind(audioService.defaultSpeaker, 'volume'), bind(audioService.defaultSpeaker, 'mute')], () => {
|
|
||||||
handleReveal(self, 'visible');
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -149,25 +73,25 @@ export const windowSetup = (self: Widget.Window): void => {
|
|||||||
*/
|
*/
|
||||||
export const revealerSetup = (self: Widget.Revealer): void => {
|
export const revealerSetup = (self: Widget.Revealer): void => {
|
||||||
self.hook(enable, () => {
|
self.hook(enable, () => {
|
||||||
handleReveal(self, 'revealChild');
|
handleReveal(self);
|
||||||
});
|
});
|
||||||
|
|
||||||
self.hook(brightnessService, 'notify::screen', () => {
|
self.hook(brightnessService, 'notify::screen', () => {
|
||||||
handleReveal(self, 'revealChild');
|
handleReveal(self);
|
||||||
});
|
});
|
||||||
|
|
||||||
self.hook(brightnessService, 'notify::kbd', () => {
|
self.hook(brightnessService, 'notify::kbd', () => {
|
||||||
handleReveal(self, 'revealChild');
|
handleReveal(self);
|
||||||
});
|
});
|
||||||
|
|
||||||
Variable.derive(
|
Variable.derive(
|
||||||
[bind(audioService.defaultMicrophone, 'volume'), bind(audioService.defaultMicrophone, 'mute')],
|
[bind(audioService.defaultMicrophone, 'volume'), bind(audioService.defaultMicrophone, 'mute')],
|
||||||
() => {
|
() => {
|
||||||
handleReveal(self, 'revealChild');
|
handleReveal(self);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
Variable.derive([bind(audioService.defaultSpeaker, 'volume'), bind(audioService.defaultSpeaker, 'mute')], () => {
|
Variable.derive([bind(audioService.defaultSpeaker, 'volume'), bind(audioService.defaultSpeaker, 'mute')], () => {
|
||||||
handleReveal(self, 'revealChild');
|
handleReveal(self);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import options from 'src/options';
|
|||||||
import { getPosition } from 'src/lib/utils';
|
import { getPosition } from 'src/lib/utils';
|
||||||
import { bind } from 'astal';
|
import { bind } from 'astal';
|
||||||
import { Astal } from 'astal/gtk3';
|
import { Astal } from 'astal/gtk3';
|
||||||
import { getOsdMonitor, windowSetup } from './helpers';
|
import { getOsdMonitor } from './helpers';
|
||||||
import { OsdRevealer } from './OsdRevealer';
|
import { OsdRevealer } from './OsdRevealer';
|
||||||
|
|
||||||
const { location } = options.theme.osd;
|
const { location } = options.theme.osd;
|
||||||
@@ -10,14 +10,18 @@ const { location } = options.theme.osd;
|
|||||||
export default (): JSX.Element => {
|
export default (): JSX.Element => {
|
||||||
return (
|
return (
|
||||||
<window
|
<window
|
||||||
monitor={getOsdMonitor()}
|
monitor={getOsdMonitor()()}
|
||||||
name={'indicator'}
|
name={'indicator'}
|
||||||
namespace={'indicator'}
|
namespace={'indicator'}
|
||||||
className={'indicator'}
|
className={'indicator'}
|
||||||
visible={false}
|
visible={true}
|
||||||
layer={bind(options.tear).as((tear) => (tear ? Astal.Layer.TOP : Astal.Layer.OVERLAY))}
|
layer={bind(options.tear).as((tear) => (tear ? Astal.Layer.TOP : Astal.Layer.OVERLAY))}
|
||||||
anchor={bind(location).as((anchorPoint) => getPosition(anchorPoint))}
|
anchor={bind(location).as((anchorPoint) => getPosition(anchorPoint))}
|
||||||
setup={windowSetup}
|
setup={(self) => {
|
||||||
|
getOsdMonitor().subscribe(() => {
|
||||||
|
self.set_click_through(true);
|
||||||
|
});
|
||||||
|
}}
|
||||||
clickThrough
|
clickThrough
|
||||||
>
|
>
|
||||||
<OsdRevealer />
|
<OsdRevealer />
|
||||||
|
|||||||
@@ -42,13 +42,14 @@ export const OSDSettings = (): JSX.Element => {
|
|||||||
subtitle="OSD follows monitor of cursor"
|
subtitle="OSD follows monitor of cursor"
|
||||||
type="boolean"
|
type="boolean"
|
||||||
/>
|
/>
|
||||||
<Option opt={options.theme.osd.radius} title="Radius" subtitle="Radius of the OSD" type="string" />
|
|
||||||
<Option
|
<Option
|
||||||
opt={options.theme.osd.margins}
|
opt={options.theme.osd.margins}
|
||||||
title="Margins"
|
title="Margins"
|
||||||
subtitle="Format: top right bottom left"
|
subtitle="Format: top right bottom left"
|
||||||
type="string"
|
type="string"
|
||||||
/>
|
/>
|
||||||
|
<Option opt={options.theme.osd.border.size} title="Border Size" type="string" />
|
||||||
|
<Option opt={options.theme.osd.radius} title="Radius" subtitle="Radius of the OSD" type="string" />
|
||||||
<Option
|
<Option
|
||||||
opt={options.theme.osd.muted_zero}
|
opt={options.theme.osd.muted_zero}
|
||||||
title="Mute Volume as Zero"
|
title="Mute Volume as Zero"
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ export const OsdTheme = (): JSX.Element => {
|
|||||||
min={0}
|
min={0}
|
||||||
max={100}
|
max={100}
|
||||||
/>
|
/>
|
||||||
|
<Option opt={options.theme.osd.border.color} title="Border" type="color" />
|
||||||
<Option opt={options.theme.osd.bar_color} title="Bar" type="color" />
|
<Option opt={options.theme.osd.bar_color} title="Bar" type="color" />
|
||||||
<Option
|
<Option
|
||||||
opt={options.theme.osd.bar_overflow_color}
|
opt={options.theme.osd.bar_overflow_color}
|
||||||
|
|||||||
@@ -134,6 +134,10 @@ const options = mkOptions(CONFIG, {
|
|||||||
enable: opt(true),
|
enable: opt(true),
|
||||||
orientation: opt<OSDOrientation>('vertical'),
|
orientation: opt<OSDOrientation>('vertical'),
|
||||||
opacity: opt(100),
|
opacity: opt(100),
|
||||||
|
border: {
|
||||||
|
size: opt('0em'),
|
||||||
|
color: opt(colors.lavender),
|
||||||
|
},
|
||||||
bar_container: opt(colors.crust),
|
bar_container: opt(colors.crust),
|
||||||
icon_container: opt(tertiary_colors.lavender),
|
icon_container: opt(tertiary_colors.lavender),
|
||||||
bar_color: opt(tertiary_colors.lavender),
|
bar_color: opt(tertiary_colors.lavender),
|
||||||
|
|||||||
@@ -9,14 +9,22 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.osd-label-container {
|
.osd-label-container {
|
||||||
|
border-top: $osd-border-size solid $osd-border-color;
|
||||||
|
border-bottom: if($osd-orientation == 'horizontal', $osd-border-size solid $osd-border-color, 0em);
|
||||||
|
border-left: if($osd-orientation == 'vertical', $osd-border-size solid $osd-border-color, 0em);
|
||||||
|
border-right: $osd-border-size solid $osd-border-color;
|
||||||
background: $osd-bar_container;
|
background: $osd-bar_container;
|
||||||
|
|
||||||
border-radius: if($osd-orientation =="vertical", $osd-radius $osd-radius 0em 0em, 0em $osd-radius $osd-radius 0em);
|
border-radius: if(
|
||||||
|
$osd-orientation == 'vertical',
|
||||||
|
$osd-radius $osd-radius 0em 0em,
|
||||||
|
0em $osd-radius $osd-radius 0em
|
||||||
|
);
|
||||||
|
|
||||||
.osd-label {
|
.osd-label {
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
padding-top: if($osd-orientation =="vertical", 1em, 0em);
|
padding-top: if($osd-orientation == 'vertical', 1em, 0em);
|
||||||
padding-right: if($osd-orientation =="horizontal", 1em, 0em);
|
padding-right: if($osd-orientation == 'horizontal', 1em, 0em);
|
||||||
color: $osd-label;
|
color: $osd-label;
|
||||||
|
|
||||||
&.overflow {
|
&.overflow {
|
||||||
@@ -26,18 +34,30 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.osd-icon-container {
|
.osd-icon-container {
|
||||||
|
border-top: if($osd-orientation == 'horizontal', $osd-border-size solid $osd-border-color, 0em);
|
||||||
|
border-bottom: $osd-border-size solid $osd-border-color;
|
||||||
|
border-left: $osd-border-size solid $osd-border-color;
|
||||||
|
border-right: if($osd-orientation == 'vertical', $osd-border-size solid $osd-border-color, 0em);
|
||||||
background: $osd-icon_container;
|
background: $osd-icon_container;
|
||||||
|
|
||||||
border-radius: if($osd-orientation =="vertical", 0em 0em $osd-radius $osd-radius, $osd-radius 0em 0em $osd-radius );
|
border-radius: if(
|
||||||
|
$osd-orientation == 'vertical',
|
||||||
|
0em 0em $osd-radius $osd-radius,
|
||||||
|
$osd-radius 0em 0em $osd-radius
|
||||||
|
);
|
||||||
|
|
||||||
.osd-icon {
|
.osd-icon {
|
||||||
font-size: 2.1em;
|
font-size: 2.1em;
|
||||||
padding: if($osd-orientation =="vertical", 0.2em 0em, 0em 0.4em);
|
padding: if($osd-orientation == 'vertical', 0.2em 0em, 0em 0.4em);
|
||||||
color: $osd-icon;
|
color: $osd-icon;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.osd-bar-container {
|
.osd-bar-container {
|
||||||
|
border-top: if($osd-orientation == 'horizontal', $osd-border-size solid $osd-border-color, 0em);
|
||||||
|
border-bottom: if($osd-orientation == 'horizontal', $osd-border-size solid $osd-border-color, 0em);
|
||||||
|
border-left: if($osd-orientation == 'vertical', $osd-border-size solid $osd-border-color, 0em);
|
||||||
|
border-right: if($osd-orientation == 'vertical', $osd-border-size solid $osd-border-color, 0em);
|
||||||
padding: 1.25em;
|
padding: 1.25em;
|
||||||
background: $osd-bar_container;
|
background: $osd-bar_container;
|
||||||
|
|
||||||
@@ -47,8 +67,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
trough {
|
trough {
|
||||||
min-height: if($osd-orientation =="vertical", 10em, 0);
|
min-height: if($osd-orientation == 'vertical', 10em, 0);
|
||||||
min-width: if($osd-orientation =="horizontal", 10em, 0);
|
min-width: if($osd-orientation == 'horizontal', 10em, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
block {
|
block {
|
||||||
@@ -56,7 +76,6 @@
|
|||||||
|
|
||||||
&.empty {
|
&.empty {
|
||||||
background: $osd-bar_empty_color;
|
background: $osd-bar_empty_color;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.filled {
|
&.filled {
|
||||||
|
|||||||
Reference in New Issue
Block a user