Added ags
TODO copy ags config
This commit is contained in:
41
roles/ags/files/widget/overview/Overview.ts
Normal file
41
roles/ags/files/widget/overview/Overview.ts
Normal file
@@ -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),
|
||||
})
|
||||
48
roles/ags/files/widget/overview/Window.ts
Normal file
48
roles/ags/files/widget/overview/Window.ts
Normal file
@@ -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),
|
||||
})
|
||||
76
roles/ags/files/widget/overview/Workspace.ts
Normal file
76
roles/ags/files/widget/overview/Workspace.ts
Normal file
@@ -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,
|
||||
}),
|
||||
})
|
||||
}
|
||||
34
roles/ags/files/widget/overview/overview.scss
Normal file
34
roles/ags/files/widget/overview/overview.scss
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user