feat: fake screen rounding
This commit is contained in:
parent
70a54153de
commit
8fab7d4b65
5 changed files with 150 additions and 52 deletions
2
app.tsx
2
app.tsx
|
|
@ -2,6 +2,7 @@ import Bar from "@/modules/bar";
|
||||||
import Launcher from "@/modules/launcher";
|
import Launcher from "@/modules/launcher";
|
||||||
import NotifPopups from "@/modules/notifpopups";
|
import NotifPopups from "@/modules/notifpopups";
|
||||||
import Osds from "@/modules/osds";
|
import Osds from "@/modules/osds";
|
||||||
|
import ScreenCorners from "@/modules/screencorners";
|
||||||
import Session from "@/modules/session";
|
import Session from "@/modules/session";
|
||||||
import SideBar from "@/modules/sidebar";
|
import SideBar from "@/modules/sidebar";
|
||||||
import Calendar from "@/services/calendar";
|
import Calendar from "@/services/calendar";
|
||||||
|
|
@ -75,6 +76,7 @@ App.start({
|
||||||
<Session />;
|
<Session />;
|
||||||
Monitors.get_default().forEach(m => <SideBar monitor={m} />);
|
Monitors.get_default().forEach(m => <SideBar monitor={m} />);
|
||||||
Monitors.get_default().forEach(m => <Bar monitor={m} />);
|
Monitors.get_default().forEach(m => <Bar monitor={m} />);
|
||||||
|
Monitors.get_default().forEach(m => <ScreenCorners monitor={m} />);
|
||||||
|
|
||||||
// Init services
|
// Init services
|
||||||
timeout(1000, () => {
|
timeout(1000, () => {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,12 @@ label.icon {
|
||||||
@include font.icon;
|
@include font.icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.screen-corner {
|
||||||
|
@include lib.rounded(15);
|
||||||
|
|
||||||
|
background-color: scheme.$mantle;
|
||||||
|
}
|
||||||
|
|
||||||
.notification {
|
.notification {
|
||||||
.inner {
|
.inner {
|
||||||
@include lib.rounded(8);
|
@include lib.rounded(8);
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import { bindCurrentTime, osIcon } from "@/utils/system";
|
||||||
import type { AstalWidget } from "@/utils/types";
|
import type { AstalWidget } from "@/utils/types";
|
||||||
import { setupCustomTooltip } from "@/utils/widgets";
|
import { setupCustomTooltip } from "@/utils/widgets";
|
||||||
import type PopupWindow from "@/widgets/popupwindow";
|
import type PopupWindow from "@/widgets/popupwindow";
|
||||||
|
import ScreenCorner from "@/widgets/screencorner";
|
||||||
import { execAsync, Variable } from "astal";
|
import { execAsync, Variable } from "astal";
|
||||||
import Binding, { bind, kebabify } from "astal/binding";
|
import Binding, { bind, kebabify } from "astal/binding";
|
||||||
import { App, Astal, Gtk } from "astal/gtk3";
|
import { App, Astal, Gtk } from "astal/gtk3";
|
||||||
|
|
@ -560,63 +561,79 @@ const bindWidget = (module: keyof typeof config.modules, Widget: () => JSX.Eleme
|
||||||
const bindCompositeWidget = (module: keyof typeof config.modules, binding: Binding<JSX.Element>) =>
|
const bindCompositeWidget = (module: keyof typeof config.modules, binding: Binding<JSX.Element>) =>
|
||||||
bind(Variable.derive([config.modules[module].enabled, binding], (e, w) => (e ? w : <Dummy />)));
|
bind(Variable.derive([config.modules[module].enabled, binding], (e, w) => (e ? w : <Dummy />)));
|
||||||
|
|
||||||
export default ({ monitor }: { monitor: Monitor }) => {
|
const Bar = ({ monitor }: { monitor: Monitor }) => {
|
||||||
const className = Variable.derive(
|
const className = Variable.derive(
|
||||||
[bind(config.vertical), bind(config.style)],
|
[bind(config.vertical), bind(config.style)],
|
||||||
(v, s) => `bar ${v ? "vertical" : " horizontal"} ${s}`
|
(v, s) => `bar ${v ? "vertical" : " horizontal"} ${s}`
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<window
|
<centerbox vertical={bind(config.vertical)} className={bind(className)} onDestroy={() => className.drop()}>
|
||||||
namespace="caelestia-bar"
|
<box vertical={bind(config.vertical)}>
|
||||||
monitor={monitor.id}
|
{bindWidget("osIcon", OSIcon)}
|
||||||
anchor={bind(config.vertical).as(
|
{bindWidget("activeWindow", ActiveWindow)}
|
||||||
v =>
|
{bindWidget("mediaPlaying", MediaPlaying)}
|
||||||
Astal.WindowAnchor.TOP |
|
<button
|
||||||
Astal.WindowAnchor.LEFT |
|
expand
|
||||||
(v ? Astal.WindowAnchor.BOTTOM : Astal.WindowAnchor.RIGHT)
|
onScroll={(_, event) =>
|
||||||
)}
|
event.delta_y > 0 ? (monitor.brightness -= 0.1) : (monitor.brightness += 0.1)
|
||||||
exclusivity={Astal.Exclusivity.EXCLUSIVE}
|
}
|
||||||
>
|
/>
|
||||||
<centerbox vertical={bind(config.vertical)} className={bind(className)} onDestroy={() => className.drop()}>
|
</box>
|
||||||
<box vertical={bind(config.vertical)}>
|
{bindWidget("workspaces", Workspaces)}
|
||||||
{bindWidget("osIcon", OSIcon)}
|
<box vertical={bind(config.vertical)}>
|
||||||
{bindWidget("activeWindow", ActiveWindow)}
|
<button
|
||||||
{bindWidget("mediaPlaying", MediaPlaying)}
|
expand
|
||||||
<button
|
onScroll={(_, event) => {
|
||||||
expand
|
const speaker = AstalWp.get_default()?.audio.defaultSpeaker;
|
||||||
onScroll={(_, event) =>
|
if (!speaker) return console.error("Unable to connect to WirePlumber.");
|
||||||
event.delta_y > 0 ? (monitor.brightness -= 0.1) : (monitor.brightness += 0.1)
|
speaker.mute = false;
|
||||||
}
|
if (event.delta_y > 0) speaker.volume -= 0.1;
|
||||||
/>
|
else speaker.volume += 0.1;
|
||||||
</box>
|
}}
|
||||||
{bindWidget("workspaces", Workspaces)}
|
/>
|
||||||
<box vertical={bind(config.vertical)}>
|
{bindWidget("tray", Tray)}
|
||||||
<button
|
{bindWidget("statusIcons", StatusIcons)}
|
||||||
expand
|
{bindWidget("pkgUpdates", PkgUpdates)}
|
||||||
onScroll={(_, event) => {
|
{bindWidget("notifCount", NotifCount)}
|
||||||
const speaker = AstalWp.get_default()?.audio.defaultSpeaker;
|
{bindCompositeWidget(
|
||||||
if (!speaker) return console.error("Unable to connect to WirePlumber.");
|
"battery",
|
||||||
speaker.mute = false;
|
bind(AstalBattery.get_default(), "isBattery").as(b => (b ? <Battery /> : <Dummy />))
|
||||||
if (event.delta_y > 0) speaker.volume -= 0.1;
|
)}
|
||||||
else speaker.volume += 0.1;
|
{bindCompositeWidget(
|
||||||
}}
|
"dateTime",
|
||||||
/>
|
bind(config.vertical).as(v => (v ? <DateTimeVertical /> : <DateTime />))
|
||||||
{bindWidget("tray", Tray)}
|
)}
|
||||||
{bindWidget("statusIcons", StatusIcons)}
|
{bindWidget("power", Power)}
|
||||||
{bindWidget("pkgUpdates", PkgUpdates)}
|
</box>
|
||||||
{bindWidget("notifCount", NotifCount)}
|
</centerbox>
|
||||||
{bindCompositeWidget(
|
|
||||||
"battery",
|
|
||||||
bind(AstalBattery.get_default(), "isBattery").as(b => (b ? <Battery /> : <Dummy />))
|
|
||||||
)}
|
|
||||||
{bindCompositeWidget(
|
|
||||||
"dateTime",
|
|
||||||
bind(config.vertical).as(v => (v ? <DateTimeVertical /> : <DateTime />))
|
|
||||||
)}
|
|
||||||
{bindWidget("power", Power)}
|
|
||||||
</box>
|
|
||||||
</centerbox>
|
|
||||||
</window>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default ({ monitor }: { monitor: Monitor }) => (
|
||||||
|
<window
|
||||||
|
namespace="caelestia-bar"
|
||||||
|
monitor={monitor.id}
|
||||||
|
anchor={bind(config.vertical).as(
|
||||||
|
v =>
|
||||||
|
Astal.WindowAnchor.TOP |
|
||||||
|
Astal.WindowAnchor.LEFT |
|
||||||
|
(v ? Astal.WindowAnchor.BOTTOM : Astal.WindowAnchor.RIGHT)
|
||||||
|
)}
|
||||||
|
exclusivity={Astal.Exclusivity.EXCLUSIVE}
|
||||||
|
>
|
||||||
|
<overlay
|
||||||
|
passThrough
|
||||||
|
overlays={[
|
||||||
|
<ScreenCorner place="topleft" />,
|
||||||
|
<ScreenCorner
|
||||||
|
halign={bind(config.vertical).as(v => (v ? undefined : Gtk.Align.END))}
|
||||||
|
valign={bind(config.vertical).as(v => (v ? Gtk.Align.END : undefined))}
|
||||||
|
place={bind(config.vertical).as(v => (v ? "bottomleft" : "topright"))}
|
||||||
|
/>,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Bar monitor={monitor} />
|
||||||
|
</overlay>
|
||||||
|
</window>
|
||||||
|
);
|
||||||
|
|
|
||||||
24
src/modules/screencorners.tsx
Normal file
24
src/modules/screencorners.tsx
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
import type { Monitor } from "@/services/monitors";
|
||||||
|
import ScreenCorner from "@/widgets/screencorner";
|
||||||
|
import { bind } from "astal/binding";
|
||||||
|
import { Astal } from "astal/gtk3";
|
||||||
|
import { bar } from "config";
|
||||||
|
|
||||||
|
export default ({ monitor }: { monitor: Monitor }) => (
|
||||||
|
<window
|
||||||
|
namespace="caelestia-screencorners"
|
||||||
|
monitor={monitor.id}
|
||||||
|
anchor={bind(bar.vertical).as(
|
||||||
|
v =>
|
||||||
|
Astal.WindowAnchor.BOTTOM |
|
||||||
|
Astal.WindowAnchor.RIGHT |
|
||||||
|
(v ? Astal.WindowAnchor.TOP : Astal.WindowAnchor.LEFT)
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<box vertical={bind(bar.vertical)}>
|
||||||
|
<ScreenCorner place={bind(bar.vertical).as(v => (v ? "topright" : "bottomleft"))} />
|
||||||
|
<box expand />
|
||||||
|
<ScreenCorner place="bottomright" />
|
||||||
|
</box>
|
||||||
|
</window>
|
||||||
|
);
|
||||||
49
src/widgets/screencorner.tsx
Normal file
49
src/widgets/screencorner.tsx
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
import type { Binding } from "astal";
|
||||||
|
import { Gtk, type Widget } from "astal/gtk3";
|
||||||
|
import type cairo from "cairo";
|
||||||
|
|
||||||
|
type Place = "topleft" | "topright" | "bottomleft" | "bottomright";
|
||||||
|
|
||||||
|
export default ({ place, ...rest }: Widget.DrawingAreaProps & { place: Place | Binding<Place> }) => (
|
||||||
|
<drawingarea
|
||||||
|
{...rest}
|
||||||
|
className="screen-corner"
|
||||||
|
setup={self => {
|
||||||
|
self.connect("realize", () => self.get_window()?.set_pass_through(true));
|
||||||
|
|
||||||
|
const r = self.get_style_context().get_property("border-radius", Gtk.StateFlags.NORMAL) as number;
|
||||||
|
self.set_size_request(r, r);
|
||||||
|
self.connect("draw", (_, cr: cairo.Context) => {
|
||||||
|
const c = self.get_style_context().get_background_color(Gtk.StateFlags.NORMAL);
|
||||||
|
const r = self.get_style_context().get_property("border-radius", Gtk.StateFlags.NORMAL) as number;
|
||||||
|
self.set_size_request(r, r);
|
||||||
|
|
||||||
|
switch (typeof place === "string" ? place : place.get()) {
|
||||||
|
case "topleft":
|
||||||
|
cr.arc(r, r, r, Math.PI, (3 * Math.PI) / 2);
|
||||||
|
cr.lineTo(0, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "topright":
|
||||||
|
cr.arc(0, r, r, (3 * Math.PI) / 2, 2 * Math.PI);
|
||||||
|
cr.lineTo(r, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "bottomleft":
|
||||||
|
cr.arc(r, 0, r, Math.PI / 2, Math.PI);
|
||||||
|
cr.lineTo(0, r);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "bottomright":
|
||||||
|
cr.arc(0, 0, r, 0, Math.PI / 2);
|
||||||
|
cr.lineTo(r, r);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cr.closePath();
|
||||||
|
cr.setSourceRGBA(c.red, c.green, c.blue, c.alpha);
|
||||||
|
cr.fill();
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
Loading…
Add table
Reference in a new issue