diff options
Diffstat (limited to 'linux/home/.config/ags/widget/overview')
| -rw-r--r-- | linux/home/.config/ags/widget/overview/Overview.ts | 41 | ||||
| -rw-r--r-- | linux/home/.config/ags/widget/overview/Window.ts | 48 | ||||
| -rw-r--r-- | linux/home/.config/ags/widget/overview/Workspace.ts | 76 | ||||
| -rw-r--r-- | linux/home/.config/ags/widget/overview/overview.scss | 34 |
4 files changed, 199 insertions, 0 deletions
diff --git a/linux/home/.config/ags/widget/overview/Overview.ts b/linux/home/.config/ags/widget/overview/Overview.ts new file mode 100644 index 0000000..8911920 --- /dev/null +++ b/linux/home/.config/ags/widget/overview/Overview.ts @@ -0,0 +1,41 @@ +import PopupWindow from "widget/PopupWindow" +import Workspace from "./Workspace" +import options from "options" +import { range } from "lib/utils" + +const hyprland = await Service.import("hyprland") + +const Overview = (ws: number) => Widget.Box({ + class_name: "overview horizontal", + children: ws > 0 + ? range(ws).map(Workspace) + : hyprland.workspaces + .map(({ id }) => Workspace(id)) + .sort((a, b) => a.attribute.id - b.attribute.id), + + setup: w => { + if (ws > 0) + return + + w.hook(hyprland, (w, id?: string) => { + if (id === undefined) + return + + w.children = w.children + .filter(ch => ch.attribute.id !== Number(id)) + }, "workspace-removed") + w.hook(hyprland, (w, id?: string) => { + if (id === undefined) + return + + w.children = [...w.children, Workspace(Number(id))] + .sort((a, b) => a.attribute.id - b.attribute.id) + }, "workspace-added") + }, +}) + +export default () => PopupWindow({ + name: "overview", + layout: "center", + child: options.overview.workspaces.bind().as(Overview), +}) diff --git a/linux/home/.config/ags/widget/overview/Window.ts b/linux/home/.config/ags/widget/overview/Window.ts new file mode 100644 index 0000000..02f71eb --- /dev/null +++ b/linux/home/.config/ags/widget/overview/Window.ts @@ -0,0 +1,48 @@ +import { type Client } from "types/service/hyprland" +import { createSurfaceFromWidget, icon } from "lib/utils" +import Gdk from "gi://Gdk" +import Gtk from "gi://Gtk?version=3.0" +import options from "options" +import icons from "lib/icons" + +const monochrome = options.overview.monochromeIcon +const TARGET = [Gtk.TargetEntry.new("text/plain", Gtk.TargetFlags.SAME_APP, 0)] +const hyprland = await Service.import("hyprland") +const apps = await Service.import("applications") +const dispatch = (args: string) => hyprland.messageAsync(`dispatch ${args}`) + +export default ({ address, size: [w, h], class: c, title }: Client) => Widget.Button({ + class_name: "client", + attribute: { address }, + tooltip_text: `${title}`, + child: Widget.Icon({ + css: options.overview.scale.bind().as(v => ` + min-width: ${(v / 100) * w}px; + min-height: ${(v / 100) * h}px; + `), + icon: monochrome.bind().as(m => { + const app = apps.list.find(app => app.match(c)) + if (!app) + return icons.fallback.executable + (m ? "-symbolic" : "") + + + return icon( + app.icon_name + (m ? "-symbolic" : ""), + icons.fallback.executable + (m ? "-symbolic" : ""), + ) + }), + }), + on_secondary_click: () => dispatch(`closewindow address:${address}`), + on_clicked: () => { + dispatch(`focuswindow address:${address}`) + App.closeWindow("overview") + }, + setup: btn => btn + .on("drag-data-get", (_w, _c, data) => data.set_text(address, address.length)) + .on("drag-begin", (_, context) => { + Gtk.drag_set_icon_surface(context, createSurfaceFromWidget(btn)) + btn.toggleClassName("hidden", true) + }) + .on("drag-end", () => btn.toggleClassName("hidden", false)) + .drag_source_set(Gdk.ModifierType.BUTTON1_MASK, TARGET, Gdk.DragAction.COPY), +}) diff --git a/linux/home/.config/ags/widget/overview/Workspace.ts b/linux/home/.config/ags/widget/overview/Workspace.ts new file mode 100644 index 0000000..1b8d60b --- /dev/null +++ b/linux/home/.config/ags/widget/overview/Workspace.ts @@ -0,0 +1,76 @@ +import Window from "./Window" +import Gdk from "gi://Gdk" +import Gtk from "gi://Gtk?version=3.0" +import options from "options" + +const TARGET = [Gtk.TargetEntry.new("text/plain", Gtk.TargetFlags.SAME_APP, 0)] +const scale = (size: number) => (options.overview.scale.value / 100) * size +const hyprland = await Service.import("hyprland") + +const dispatch = (args: string) => hyprland.messageAsync(`dispatch ${args}`) + +const size = (id: number) => { + const def = { h: 1080, w: 1920 } + const ws = hyprland.getWorkspace(id) + if (!ws) + return def + + const mon = hyprland.getMonitor(ws.monitorID) + return mon ? { h: mon.height, w: mon.width } : def +} + +export default (id: number) => { + const fixed = Widget.Fixed() + + // TODO: early return if position is unchaged + async function update() { + const json = await hyprland.messageAsync("j/clients").catch(() => null) + if (!json) + return + + fixed.get_children().forEach(ch => ch.destroy()) + const clients = JSON.parse(json) as typeof hyprland.clients + clients + .filter(({ workspace }) => workspace.id === id) + .forEach(c => { + const x = c.at[0] - (hyprland.getMonitor(c.monitor)?.x || 0) + const y = c.at[1] - (hyprland.getMonitor(c.monitor)?.y || 0) + c.mapped && fixed.put(Window(c), scale(x), scale(y)) + }) + fixed.show_all() + } + + return Widget.Box({ + attribute: { id }, + tooltipText: `${id}`, + class_name: "workspace", + vpack: "center", + css: options.overview.scale.bind().as(v => ` + min-width: ${(v / 100) * size(id).w}px; + min-height: ${(v / 100) * size(id).h}px; + `), + setup(box) { + box.hook(options.overview.scale, update) + box.hook(hyprland, update, "notify::clients") + box.hook(hyprland.active.client, update) + box.hook(hyprland.active.workspace, () => { + box.toggleClassName("active", hyprland.active.workspace.id === id) + }) + }, + child: Widget.EventBox({ + expand: true, + on_primary_click: () => { + App.closeWindow("overview") + dispatch(`workspace ${id}`) + }, + setup: eventbox => { + eventbox.drag_dest_set(Gtk.DestDefaults.ALL, TARGET, Gdk.DragAction.COPY) + eventbox.connect("drag-data-received", (_w, _c, _x, _y, data) => { + const address = new TextDecoder().decode(data.get_data()) + dispatch(`movetoworkspacesilent ${id},address:${address}`) + }) + }, + child: fixed, + }), + }) +} diff --git a/linux/home/.config/ags/widget/overview/overview.scss b/linux/home/.config/ags/widget/overview/overview.scss new file mode 100644 index 0000000..4665b52 --- /dev/null +++ b/linux/home/.config/ags/widget/overview/overview.scss @@ -0,0 +1,34 @@ +window#overview .overview { + @include floating-widget; + @include spacing; + + .workspace { + &.active>widget { + border-color: $primary-bg; + } + + >widget { + @include widget; + border-radius: if($radius ==0, 0, $radius + $padding); + + &:hover { + background-color: $hover-bg; + } + + &:drop(active) { + border-color: $primary-bg; + } + } + } + + .client { + @include button; + border-radius: $radius; + margin: $padding; + + &.hidden { + @include hidden; + transition: 0; + } + } +} |
