← back to festeh__dotfiles

Function bodies 110 total

All specs Real LLM only Function bodies
getBestMonitor function · typescript · L16-L28 (13 LOC)
ags/app.ts
function getBestMonitor() {
  let monitor: Gdk.Monitor | null = null
  let width = -1
  const monitors = display.get_monitors()
  for (let idx = 0; idx < monitors.get_n_items(); idx++) {
    const m = monitors.get_item(idx) as Gdk.Monitor;
    if (m.get_geometry().width > width) {
      width = m.get_geometry().width
      monitor = m
    }
  }
  return monitor
}
initWidgets function · typescript · L36-L42 (7 LOC)
ags/app.ts
function initWidgets(monitor: Gdk.Monitor) {
  return [
    Bar(monitor, calendarVisible, currentDate),
    Calendar(monitor, calendarVisible, currentDate),
    Notifications(monitor)
  ]
}
WorkspaceNamingService class · typescript · L4-L94 (91 LOC)
ags/service/WorkspaceNaming.ts
class WorkspaceNamingService {
  private hypr = Hyprland.get_default()

  constructor() {
    // Track previous workspace of windows for move detection
    const windowWorkspaces = new Map<string, number>()

    this.hypr.connect("event", (_, eventName, args) => {
      const parts = args.split(",")

      switch (eventName) {
        case "movewindowv2": {
          const address = parts[0]
          const destWorkspaceId = parseInt(parts[1])
          const sourceWorkspaceId = windowWorkspaces.get(address)

          if (sourceWorkspaceId) this.updateWorkspaceName(sourceWorkspaceId)
          this.updateWorkspaceName(destWorkspaceId)

          windowWorkspaces.set(address, destWorkspaceId)
          break
        }

        case "activewindowv2": {
          const client = this.hypr.get_client(parts[0])
          const workspace = client?.get_workspace()
          if (client && workspace) {
            const wsId = workspace.get_id()
            this.updateWorkspaceName(wsId)
      
constructor method · typescript · L7-L48 (42 LOC)
ags/service/WorkspaceNaming.ts
  constructor() {
    // Track previous workspace of windows for move detection
    const windowWorkspaces = new Map<string, number>()

    this.hypr.connect("event", (_, eventName, args) => {
      const parts = args.split(",")

      switch (eventName) {
        case "movewindowv2": {
          const address = parts[0]
          const destWorkspaceId = parseInt(parts[1])
          const sourceWorkspaceId = windowWorkspaces.get(address)

          if (sourceWorkspaceId) this.updateWorkspaceName(sourceWorkspaceId)
          this.updateWorkspaceName(destWorkspaceId)

          windowWorkspaces.set(address, destWorkspaceId)
          break
        }

        case "activewindowv2": {
          const client = this.hypr.get_client(parts[0])
          const workspace = client?.get_workspace()
          if (client && workspace) {
            const wsId = workspace.get_id()
            this.updateWorkspaceName(wsId)
            windowWorkspaces.set(parts[0], wsId)
          }
          break
 
getKittyCwd method · typescript · L50-L59 (10 LOC)
ags/service/WorkspaceNaming.ts
  private async getKittyCwd(pid: number): Promise<string | null> {
    try {
      const output = await execAsync(`kitty @ --to unix:@kitty-${pid} ls`)
      const data = JSON.parse(output)
      const cwd = data[0]?.tabs?.[0]?.windows?.[0]?.cwd
      return cwd || null
    } catch {
      return null
    }
  }
updateWorkspaceName method · typescript · L61-L84 (24 LOC)
ags/service/WorkspaceNaming.ts
  private async updateWorkspaceName(workspaceId: number) {
    const workspace = this.hypr.get_workspace(workspaceId)
    if (!workspace) return

    // Find kitty client in this workspace
    const kittyClient = this.hypr.get_clients().find(
      (client) => client.get_workspace()?.get_id() === workspaceId &&
                  client.get_class() === "kitty"
    )

    let newName = workspaceId.toString()

    if (kittyClient) {
      const cwd = await this.getKittyCwd(kittyClient.get_pid())
      if (cwd) {
        const parts = cwd.split("/")
        newName = parts[parts.length - 1] || workspaceId.toString()
      }
    }

    if (workspace.get_name() !== newName) {
      exec(`hyprctl dispatch renameworkspace ${workspaceId} ${newName}`)
    }
  }
exec method · typescript · L82-L93 (12 LOC)
ags/service/WorkspaceNaming.ts
      exec(`hyprctl dispatch renameworkspace ${workspaceId} ${newName}`)
    }
  }

  private async updateAllWorkspaceNames() {
    const workspaces = this.hypr.get_workspaces()
      .filter((ws) => !(ws.get_id() >= -99 && ws.get_id() <= -2))

    for (const workspace of workspaces) {
      await this.updateWorkspaceName(workspace.get_id())
    }
  }
Provenance: Repobility (https://repobility.com) — every score reproducible from /scan/
Bar function · typescript · L14-L51 (38 LOC)
ags/widget/Bar.ts
export default function Bar(monitor: Gdk.Monitor, calendarVisible: Variable<boolean>,
  currentDate: Variable<Date>,
  menuVisible: Variable<boolean>,
) {
  return Widget.Window(
    {
      className: "Bar",
      visible: true,
      gdkmonitor: monitor,
      exclusivity: Astal.Exclusivity.EXCLUSIVE,
      anchor: Astal.WindowAnchor.TOP | Astal.WindowAnchor.LEFT | Astal.WindowAnchor.RIGHT,
      application: App
    },
    Widget.Box({
      className: "bar-container",
      children: [
        Widget.Box({
          hexpand: true,
          children: [
            HyprlandStatus(),
            Coach(),
          ]
        }),
        Widget.Box({
          children: [
            LayoutStatus(),
            IdleStatus(),
            MenuButton(menuVisible),
            Volume(),
            Battery(),
            TimeDate(currentDate, calendarVisible),
            Tray()
          ]
        })
      ]
    })
  )
}
Battery function · typescript · L6-L23 (18 LOC)
ags/widget/Battery.tsx
export default function Battery() {
  const bat = AstalBattery.get_default()
  return Widget.Box({
    css_classes: bind(bat, "percentage").as((p) =>
      p < 0.20 ? ["battery-widget", "battery-low"] : ["battery-widget"]
    ),
    children: [
      Widget.Image({
        iconName: bind(bat, "icon-name"),
      }),
      Widget.Label({
        label: bind(bat, "percentage").as((p) => {
          return `${Math.round(p * 100)}%`
        }),
      }),
    ],
  })
}
generateCalendarDays function · typescript · L21-L77 (57 LOC)
ags/widget/Calendar.tsx
function generateCalendarDays(currentDate: Variable<Date>) {
  const firstDay = bind(currentDate).as((date: Date) => {
    const year = date.getFullYear()
    const month = date.getMonth()
    return new Date(year, month, 1).getDay()
  })

  const daysInMonth = bind(currentDate).as((date: Date) => {
    const year = date.getFullYear()
    const month = date.getMonth()
    return new Date(year, month + 1, 0).getDate()
  })

  const days = Variable.derive(
    [firstDay, daysInMonth],
    (firstDay, daysInMonth) => {
      const d = Array(firstDay === 0 ? 6 : firstDay - 1).fill(null)
        .concat(Array.from({ length: daysInMonth }, (_, i) => i + 1))
      // Pad the array to ensure it's divisible by 7
      while (d.length % 7 !== 0) {
        d.push(null)
      }
      return d
    }
  )

  const rows = bind(days).as((d: number[]) => {
    const today = new Date()
    const todayDay = today.getDate()
    const viewedMonth = currentDate.get().getMonth()
    const viewedYear = currentD
makeWeekdayHeader function · typescript · L79-L94 (16 LOC)
ags/widget/Calendar.tsx
function makeWeekdayHeader() {
  const weekdays = ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su']
  return <box
    hexpand={true}
    halign={Gtk.Align.FILL}
    homogeneous={true}
    cssClasses={["calendar-row"]}
  >
    {weekdays.map((day: string) => (
      <label
        cssClasses={["weekday-header"]}
        label={day}
      />
    ))}
  </box>
}
Calendar function · typescript · L96-L140 (45 LOC)
ags/widget/Calendar.tsx
export default function Calendar(monitor: Gdk.Monitor, visible: Variable<boolean>, currentDate: Variable<Date>) {
  const monthName = bind(currentDate).as((date: Date) => date.toLocaleString('default', { month: 'long', year: 'numeric' }))

  const previousMonth = () => {
    const current = currentDate.get()
    const newDate = new Date(current.getFullYear(), current.getMonth() - 1, 1)
    currentDate.set(newDate)
  }

  const nextMonth = () => {
    const current = currentDate.get()
    const newDate = new Date(current.getFullYear(), current.getMonth() + 1, 1)
    currentDate.set(newDate)
  }

  return (
    <window
      gdkmonitor={monitor}
      cssClasses={["Calendar"]}
      visible={bind(visible)}
      anchor={Astal.WindowAnchor.TOP | Astal.WindowAnchor.RIGHT}
      application={App}>
      <box
        cssClasses={["calendar-widget"]}
        spacing={5}
        valign={Gtk.Align.FILL}
        orientation={Gtk.Orientation.VERTICAL}
      >
        <box cssClasses={["calendar-h
setFocusingState function · typescript · L23-L44 (22 LOC)
ags/widget/Coach.ts
function setFocusingState(focusing: boolean, duration: number, numFocuses: number) {
  const wasFocusing = isFocusing.get()
  if (wasFocusing !== focusing) {
    console.log(`Focus state changed: ${wasFocusing} -> ${focusing}`)
  }
  durationState.set(duration)
  numFocusesState.set(numFocuses)
  isFocusing.set(focusing)
  const durationMinutes = Math.floor(duration / 60)
  let durationString = ""
  if (durationMinutes == 1) {
    durationString = "for 1 minute"
  } else if (durationMinutes > 1) {
    durationString = `for ${durationMinutes} minutes`
  }
  let focusingString = "Focusing"
  if (!focusing) {
    focusingString = "Not focusing"
  }
  focusingState.set(`${focusingString} ${durationString} [${numFocuses}]`)
  changedState.set(new Date())
}
updateFocusingState function · typescript · L46-L56 (11 LOC)
ags/widget/Coach.ts
function updateFocusingState() {
  const now = new Date()
  const delta = Math.floor((now.getTime() - changedState.get().getTime()) / 1000)
  const duration = durationState.get() + delta
  let focusing = true
  if (focusingState.get().includes("Not focusing")) {
    focusing = false
  }
  const numFocuses = numFocusesState.get()
  setFocusingState(focusing, duration, numFocuses)
}
setupHeartbeat function · typescript · L58-L82 (25 LOC)
ags/widget/Coach.ts
function setupHeartbeat() {
  if (heartbeatSource !== null) {
    GLib.source_remove(heartbeatSource)
    heartbeatSource = null
  }

  // Set up a new heartbeat
  heartbeatSource = GLib.timeout_add(GLib.PRIORITY_DEFAULT, HEARTBEAT_INTERVAL, () => {
    updateFocusingState()
    if (connection && connectionState.get() === "connected") {
      if (awaitingHeartbeatResponse) {
        console.log("Previous heartbeat not answered, reconnecting")
        reconnect()
        return GLib.SOURCE_CONTINUE
      }
      console.log("Sending heartbeat get_focusing request")
      awaitingHeartbeatResponse = true
      sendWebSocketMessage(connection, { type: "get_focusing" })
    } else {
      console.log("Connection lost, attempting reconnect")
      reconnect()
    }
    return GLib.SOURCE_CONTINUE
  })
}
Repobility (the analyzer behind this table) · https://repobility.com
reconnect function · typescript · L84-L107 (24 LOC)
ags/widget/Coach.ts
function reconnect() {
  if (connectionState.get() === "connecting") {
    return
  }

  if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
    console.error("Maximum reconnection attempts reached")
    focusingState.set("Connection failed")
    return
  }

  // Exponential backoff for reconnection attempts
  const delay = BASE_RECONNECT_DELAY * Math.pow(1.5, reconnectAttempts)
  reconnectAttempts++

  console.log(`Attempting to reconnect in ${delay / 1000} seconds (attempt ${reconnectAttempts})`)
  connectionState.set("connecting")

  GLib.timeout_add(GLib.PRIORITY_DEFAULT, delay, () => {
    console.log("Reconnecting...")
    init()
    return GLib.SOURCE_REMOVE // One-time timeout
  })
}
handleWebSocketConnection function · typescript · L109-L136 (28 LOC)
ags/widget/Coach.ts
function handleWebSocketConnection(session: Soup.Session, result: Gio.AsyncResult) {
  try {
    connection = session.websocket_connect_finish(result)
    connectionState.set("connected")
    reconnectAttempts = 0
    awaitingHeartbeatResponse = false

    connection.connect("message", handleWebSocketMessage)

    connection.connect("closed", () => {
      console.log("WebSocket connection closed")
      connectionState.set("disconnected")
      connection = null

      reconnect()
    })

    setupHeartbeat()

    // sendWebSocketMessage(connection, { type: "health" })
  } catch (error) {
    console.error("WebSocket connection error:", error)
    connectionState.set("disconnected")
    connection = null

    reconnect()
  }
}
isFocusInfo function · typescript · L146-L148 (3 LOC)
ags/widget/Coach.ts
function isFocusInfo(obj: unknown): obj is FocusInfo {
  return typeof obj === "object" && obj !== null && (obj as FocusInfo).type === "focusing"
}
handleWebSocketMessage function · typescript · L150-L169 (20 LOC)
ags/widget/Coach.ts
function handleWebSocketMessage(_: any, type: Soup.WebsocketDataType, message: any) {
  if (type !== Soup.WebsocketDataType.TEXT) return

  const data = new TextDecoder().decode(message.get_data())
  console.log("Received message:", data)

  try {
    const parsed = JSON.parse(data)

    if (isFocusInfo(parsed)) {
      awaitingHeartbeatResponse = false
      setFocusingState(parsed.focusing, parsed.since_last_change, parsed.num_focuses)
    } else {
      console.error("Unknown message type:", parsed.type ?? "missing type", data)
    }

  } catch (error) {
    console.error("Error parsing message:", error)
  }
}
sendWebSocketMessage function · typescript · L172-L189 (18 LOC)
ags/widget/Coach.ts
function sendWebSocketMessage(connection: Soup.WebsocketConnection, messageObj: object) {
  if (!connection || connectionState.get() !== "connected") {
    console.warn("Cannot send message: WebSocket not connected")
    return
  }

  try {
    const data = JSON.stringify(messageObj)
    connection.send_message(
      Soup.WebsocketDataType.TEXT,
      new GLib.Bytes(new TextEncoder().encode(data))
    )
  } catch (error) {
    console.error("Error sending WebSocket message:", error)
    connectionState.set("disconnected")
    reconnect()
  }
}
init function · typescript · L191-L223 (33 LOC)
ags/widget/Coach.ts
async function init() {
  const coachUrl = GLib.getenv("COACH_URL") + "/connect"
  console.log("COACH_URL:", coachUrl)

  if (!coachUrl) {
    console.log("COACH_URL environment variable not set")
    focusingState.set("COACH_URL not set")
    return
  }

  try {
    connectionState.set("connecting")
    const session = new Soup.Session()
    const message = new Soup.Message({
      method: "GET",
      uri: GLib.Uri.parse(coachUrl, GLib.UriFlags.NONE)
    })

    session.websocket_connect_async(
      message,
      null, // origin
      null,
      1,
      null, // cancellable
      (_, result) => handleWebSocketConnection(session, result)
    )
  } catch (error) {
    console.error("Error setting up WebSocket:", error)
    connectionState.set("disconnected")
    focusingState.set("Connection error")
    reconnect()
  }
}
toggleFocus function · typescript · L225-L232 (8 LOC)
ags/widget/Coach.ts
function toggleFocus() {
  if (connection && connectionState.get() === "connected") {
    sendWebSocketMessage(connection, { type: "focus" });
    console.log("Sent focus toggle message");
  } else {
    console.warn("Cannot toggle focus: WebSocket not connected");
  }
}
Coach function · typescript · L234-L251 (18 LOC)
ags/widget/Coach.ts
export default function Coach() {
  init();

  const button = Widget.Button({
    // className: "focusing-button",
    onClicked: toggleFocus,
    child: Widget.Label({
      // className: "focusing-label",
      label: bind(focusingState),
    })
  });
  return Widget.Box({
    css_classes: bind(isFocusing).as(focusing =>
      focusing ? ["focusing-widget"] : ["focusing-widget", "not-focusing"]
    ),
    children: [button]
  })
}
Repobility analyzer · published findings · https://repobility.com
HyprlandStatus function · typescript · L7-L85 (79 LOC)
ags/widget/HyprlandStatus.ts
export default function HyprlandStatus() {
  const hypr = Hyprland.get_default()

  return Widget.Box({
    css_classes: ["workspace-widget"],
    setup: (self) => {
      const updateWorkspaces = () => {
        try {
          self.children = []

          // Get all workspaces, filter and sort
          const workspaces = hypr.get_workspaces()
          const filtered = workspaces.filter((ws) => !(ws.get_id() >= -99 && ws.get_id() <= -2))
          const sorted = filtered.sort((a, b) => a.get_id() - b.get_id())

          // Add workspace buttons
          self.children = sorted.map((ws) => {
          const getLabel = () => {
            const id = ws.get_id()
            const name = ws.get_name()
            return name === id.toString() ? name : `<span alpha="50%">${id}</span> ${name}`
          }

          const button = Widget.Button({
            child: Widget.Label({
              label: getLabel(),
              use_markup: true,
            }),
            onClicked: () =
IdleStatus function · typescript · L6-L20 (15 LOC)
ags/widget/IdleStatus.ts
export default function IdleStatus() {
  return Widget.Button({
    css_classes: ["idle-status-widget"],
    margin: 0,
    visible: bind(isIdleRunning).as(running => !running),
    child: Widget.Image({
      iconName: "face-surprise-symbolic",
      css: "font-size: 18px",
      margin: 0
    }),
    onClicked: () => {
      GLib.spawn_command_line_async('bash -c "swayidle -w timeout 1500 \'systemctl hibernate\' &"')
    },
  })
}
LayoutStatus function · typescript · L6-L18 (13 LOC)
ags/widget/LayoutStatus.ts
export default function LayoutStatus() {
  return Widget.Button({
    css_classes: ["layout-status-widget"],
    margin: 0,
    visible: bind(keyboardLayout).as(layout => layout.includes("Russian")),
    child: Widget.Image({
      file: "/home/dima/dotfiles/ags/assets/ru-tricolor.svg",
    }),
    onClicked: () => {
      GLib.spawn_command_line_async("hyprctl switchxkblayout at-translated-set-2-keyboard next")
    },
  })
}
MenuButton function · typescript · L4-L17 (14 LOC)
ags/widget/MenuButton.ts
export default function MenuButton(menuVisible: Variable<boolean>) {
  return Widget.Button({
    css_classes: ["idle-widget"],
    margin: 0,
    child: Widget.Image({
      iconName: "pan-down-symbolic",
      css: "font-size: 18px",
      margin: 0
    }),
    onClicked: () => {
      menuVisible.set(!menuVisible.get())
    },
  })
}
checkSwayidle function · typescript · L9-L16 (8 LOC)
ags/widget/Menu.tsx
function checkSwayidle(): boolean {
  try {
    const [success, stdout, stderr] = GLib.spawn_command_line_sync("pgrep swayidle")
    return stdout.length > 0
  } catch (error) {
    return false
  }
}
checkRecording function · typescript · L18-L25 (8 LOC)
ags/widget/Menu.tsx
function checkRecording(): boolean {
  try {
    const [success, stdout] = GLib.spawn_command_line_sync("pgrep -f 'ffmpeg.*pulse.*records'")
    return stdout.length > 0
  } catch (error) {
    return false
  }
}
getRecordingDuration function · typescript · L27-L32 (6 LOC)
ags/widget/Menu.tsx
function getRecordingDuration(): number {
  if (!isRecording.get()) return 0
  const startTime = recordingStartTime.get()
  if (startTime === 0) return 0
  return Math.floor((Date.now() - startTime) / 1000)
}
formatDuration function · typescript · L34-L38 (5 LOC)
ags/widget/Menu.tsx
function formatDuration(seconds: number): string {
  const mins = Math.floor(seconds / 60)
  const secs = seconds % 60
  return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`
}
All rows scored by the Repobility analyzer (https://repobility.com)
getCurrentKeyboardLayout function · typescript · L40-L59 (20 LOC)
ags/widget/Menu.tsx
function getCurrentKeyboardLayout(): string {
  try {
    const [success, stdout] = GLib.spawn_command_line_sync("hyprctl devices -j")
    if (success) {
      const devices = JSON.parse(new TextDecoder().decode(stdout))
      // Filter out virtual keyboards (like wtype) and find the main physical keyboard
      const realKeyboard = devices.keyboards.find((kb: any) =>
        kb.main && !kb.name.includes("virtual")
      ) || devices.keyboards.find((kb: any) =>
        kb.name === "at-translated-set-2-keyboard"
      )
      if (realKeyboard) {
        return realKeyboard.active_keymap || "Unknown"
      }
    }
  } catch (error) {
    console.error("Failed to get keyboard layout:", error)
  }
  return "Unknown"
}
getLanguageCode function · typescript · L73-L78 (6 LOC)
ags/widget/Menu.tsx
function getLanguageCode(): string {
  const layout = keyboardLayout.get().toLowerCase()
  if (layout.includes("russian")) return "ru"
  if (layout.includes("english")) return "en"
  return "auto"
}
startRecording function · typescript · L80-L89 (10 LOC)
ags/widget/Menu.tsx
function startRecording() {
  if (isRecording.get() || isProcessing.get()) return

  GLib.spawn_command_line_sync(`mkdir -p ${RECORDS_DIR}`)
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-')
  const filename = `${RECORDS_DIR}/record_${timestamp}.wav`
  lastRecordedFile.set(filename)
  GLib.spawn_command_line_async(`ffmpeg -f pulse -i default -ac 1 -acodec pcm_s16le -ar 16000 ${filename}`)
  recordingStartTime.set(Date.now())
}
stopRecording function · typescript · L91-L104 (14 LOC)
ags/widget/Menu.tsx
function stopRecording() {
  if (!isRecording.get() || isProcessing.get()) return

  GLib.spawn_command_line_async("pkill -f 'ffmpeg.*pulse.*records'")
  const filepath = lastRecordedFile.get()
  recordingStartTime.set(0)
  menuVisible.set(false)
  GLib.timeout_add(GLib.PRIORITY_DEFAULT, 500, () => {
    if (filepath) {
      transcribeAudio(filepath)
    }
    return false
  })
}
cancelRecording function · typescript · L106-L112 (7 LOC)
ags/widget/Menu.tsx
function cancelRecording() {
  if (!isRecording.get() || isProcessing.get()) return

  GLib.spawn_command_line_async("pkill -f 'ffmpeg.*pulse.*records'")
  recordingStartTime.set(0)
  menuVisible.set(false)
}
transcribeAudio function · typescript · L114-L152 (39 LOC)
ags/widget/Menu.tsx
async function transcribeAudio(filepath: string): Promise<void> {
  isProcessing.set(true)
  const langCode = getLanguageCode()
  try {
    const [success, stdout, stderr] = GLib.spawn_command_line_sync(
      `curl -s -X POST https://silence.dimalip.in/speak -F "audio=@${filepath}" -F "file_format=pcm_s16le_16" -F "language_code=${langCode}"`
    )
    if (success && stdout.length > 0) {
      const response = JSON.parse(new TextDecoder().decode(stdout))
      if (response.text) {
        // Copy to clipboard
        const escapedText = response.text.replace(/'/g, "'\\''")
        GLib.spawn_command_line_async(`bash -c 'echo -n "${escapedText}" | wl-copy'`)
        // Simulate keyboard input
        GLib.spawn_command_line_async(`wtype "${response.text.replace(/"/g, '\\"')}"`)
        GLib.spawn_command_line_async(
          `notify-send -a "Audio Transcription" "ASR Result (typed)" "${response.text.replace(/"/g, '\\"')}"`
        )
      } else if (response.error) {
        GLib.spaw
Menu function · typescript · L160-L295 (136 LOC)
ags/widget/Menu.tsx
export default function Menu(monitor: Gdk.Monitor) {
  const win = (
    <window
      gdkmonitor={monitor}
      cssClasses={["Menu"]}
      visible={bind(menuVisible)}
      anchor={Astal.WindowAnchor.TOP | Astal.WindowAnchor.RIGHT}
      keymode={Astal.Keymode.EXCLUSIVE}
      application={App}>
      <box
        cssClasses={["menu-widget"]}
        spacing={5}
        orientation={Gtk.Orientation.VERTICAL}
      >
        <button
          focusable={false}
          css_classes={bind(isIdleRunning).as(running =>
            running ? ["idle-toggle-button"] : ["idle-toggle-button", "idle-toggle-button-inactive"]
          )}
          onClicked={() => {
            const running = isIdleRunning.get()
            if (running) {
              GLib.spawn_command_line_async("pkill swayidle")
            } else {
              GLib.spawn_command_line_async('bash -c "swayidle -w timeout 1500 \'systemctl hibernate\' &"')
            }
          }}
        >
          <box spacing={10}>
 
NotificationHistory class · typescript · L15-L85 (71 LOC)
ags/widget/Notifications.ts
class NotificationHistory implements Subscribable {
  private map: Map<number, Gtk.Widget> = new Map()
  private subs: Variable<Array<Gtk.Widget>> = Variable([])

  private notifiy() {
    this.subs.set([...this.map.values()].reverse())
  }

  constructor() {
    const notifd = Notifd.get_default()

    // Enforce our own timeout instead of sender's timeout
    notifd.ignoreTimeout = true

    notifd.connect("notified", (_, id) => {
      const notification = notifd.get_notification(id)!
      const isPersistent = PERSISTENT_APPS.includes(notification.appName || "")

      this.set(id, Notification({
        notification,

        // Defer dismissal to next event loop iteration to avoid GTK4 crash during event processing
        onHoverLost: () => {
          timeout(1, () => notification.dismiss())
        },

        setup: () => {
          if (!isPersistent) {
            timeout(TIMEOUT_DELAY, () => {
              notification.dismiss()
            })
          }
        }
      
Provenance: Repobility (https://repobility.com) — every score reproducible from /scan/
notifiy method · typescript · L19-L21 (3 LOC)
ags/widget/Notifications.ts
  private notifiy() {
    this.subs.set([...this.map.values()].reverse())
  }
constructor method · typescript · L23-L54 (32 LOC)
ags/widget/Notifications.ts
  constructor() {
    const notifd = Notifd.get_default()

    // Enforce our own timeout instead of sender's timeout
    notifd.ignoreTimeout = true

    notifd.connect("notified", (_, id) => {
      const notification = notifd.get_notification(id)!
      const isPersistent = PERSISTENT_APPS.includes(notification.appName || "")

      this.set(id, Notification({
        notification,

        // Defer dismissal to next event loop iteration to avoid GTK4 crash during event processing
        onHoverLost: () => {
          timeout(1, () => notification.dismiss())
        },

        setup: () => {
          if (!isPersistent) {
            timeout(TIMEOUT_DELAY, () => {
              notification.dismiss()
            })
          }
        }
      }))
    })

    notifd.connect("resolved", (_, id) => {
      this.delete(id)
    })
  }
timeout method · typescript · L38-L47 (10 LOC)
ags/widget/Notifications.ts
          timeout(1, () => notification.dismiss())
        },

        setup: () => {
          if (!isPersistent) {
            timeout(TIMEOUT_DELAY, () => {
              notification.dismiss()
            })
          }
        }
timeout method · typescript · L43-L45 (3 LOC)
ags/widget/Notifications.ts
            timeout(TIMEOUT_DELAY, () => {
              notification.dismiss()
            })
set method · typescript · L56-L60 (5 LOC)
ags/widget/Notifications.ts
  private set(key: number, value: Gtk.Widget) {
    // Just update the map, GTK will handle widget replacement
    this.map.set(key, value)
    this.notifiy()
  }
get method · typescript · L77-L79 (3 LOC)
ags/widget/Notifications.ts
  get() {
    return this.subs.get()
  }
subscribe method · typescript · L82-L84 (3 LOC)
ags/widget/Notifications.ts
  subscribe(callback: (list: Array<Gtk.Widget>) => void) {
    return this.subs.subscribe(callback)
  }
Notifications function · typescript · L86-L99 (14 LOC)
ags/widget/Notifications.ts
export default function Notifications(monitor: Gdk.Monitor) {
  const history = new NotificationHistory()
  return Widget.Window({
    gdkmonitor: monitor,
    visible: bind(history).as(list => list.length > 0),
    exclusivity: Astal.Exclusivity.NORMAL,
    anchor: Astal.WindowAnchor.TOP | Astal.WindowAnchor.RIGHT,
  }, Widget.Box({
    vertical: true,
    spacing: 0,
  }, bind(history))

  )
}
Repobility (the analyzer behind this table) · https://repobility.com
Notification function · typescript · L12-L123 (112 LOC)
ags/widget/Notification.ts
export default function Notification({ notification, onHoverLost, setup }: NotificationProps): Gtk.Widget {
  // Check if appIcon is a file path or icon name
  const isFilePath = notification.appIcon?.startsWith("/") || notification.appIcon?.startsWith("~")
  const hasValidIcon = notification.appIcon && notification.appIcon !== ""

  // Check if image is valid (file path exists and is safe)
  const hasValidImage = notification.image &&
                        notification.image.trim() !== "" &&
                        (notification.image.startsWith("/") || notification.image.startsWith("~")) &&
                        !notification.image.includes("..") // Prevent path traversal

  // Filter out invalid/empty actions (must have both label and id, and label must not be empty)
  const validActions = notification.actions?.filter(action => {
    const hasValidLabel = action.label && action.label.trim() !== ""
    const hasValidId = action.id && action.id !== ""
    return hasValidLabel && h
Pomodoro function · typescript · L4-L9 (6 LOC)
ags/widget/Pomodoro.ts
export default function Pomodoro(pomodoro: Variable<string>) {
  return Widget.Label({
    className: "pomodoro-widget",
    label: bind(pomodoro)
  })
}
DateWidget function · typescript · L7-L21 (15 LOC)
ags/widget/TimeDate.ts
export default function DateWidget(currentDate, calendarVisible) {
  const button = Widget.Button({
    label: bind(time),
    // halign: Gtk.Align.CENTER,
    onClicked: () => {
      currentDate.set(new Date())
      const value = calendarVisible.get()
      calendarVisible.set(!value)
    }
  })
  return Widget.Box({
    css_classes: ["time-widget"],
    children: [button]
  })
}
page 1 / 3next ›