aboutsummaryrefslogtreecommitdiff
path: root/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace-context.jsx
blob: f780a71f39c6224e995c1a4e51276dde70f3badc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import * as Uebersicht from "uebersicht";
import { useSimpleBarContext } from "./simple-bar-context.jsx";
import useServerSocket from "../hooks/use-server-socket.js";
import * as Aerospace from "../aerospace.js";

const { React } = Uebersicht;

// Create a context with default values
const AerospaceContext = React.createContext({
  spaces: [],
  windows: [],
  mode: "",
});

/**
 * Custom hook to use the AerospaceContext
 * @returns {Object} The context value
 */
export function useAerospaceContext() {
  return React.useContext(AerospaceContext);
}

// Memoized AerospaceContextProvider component
export default React.memo(AerospaceContextProvider);

/**
 * AerospaceContextProvider component
 * @param {Object} props - The component props
 * @param {React.ReactNode} props.children - The child components
 * @returns {JSX.Element} The provider component
 */
function AerospaceContextProvider({ children }) {
  // Get settings, displayIndex, and displays from SimpleBarContext
  const { settings, displayIndex, displays } = useSimpleBarContext();
  const { enableServer, aerospaceServerRefresh } = settings.global;
  const serverEnabled = enableServer && aerospaceServerRefresh;

  // State to store aerospace spaces
  const [aerospaceSpaces, setAerospaceSpaces] = React.useState([]);
  const latestRequestRef = React.useRef(0);

  // Fetches and sets the aerospace spaces
  const getSpaces = React.useCallback(async () => {
    const requestId = latestRequestRef.current + 1;
    latestRequestRef.current = requestId;

    let focusedWindow = {};
    const [focusedSpace] = await Aerospace.getFocusedSpace();
    try {
      [focusedWindow] = await Aerospace.getFocusedWindow();
      // eslint-disable-next-line no-empty
    } catch {}
    const spaces = await Promise.all(
      displays.map(async (display) => {
        const id = display["monitor-id"];
        const result = await Aerospace.getSpaces(id);
        return Promise.all(
          result.map(async (space) => {
            const focused = space.workspace === focusedSpace.workspace;
            const monitor = Aerospace.getDisplayIndex(space);
            const windows = await Aerospace.getWindows(space.workspace);
            const formatted = windows.map((window) => {
              const focused =
                window["window-id"] === focusedWindow["window-id"];
              return {
                ...window,
                focused,
              };
            });
            return { ...space, windows: formatted, focused, monitor };
          })
        );
      })
    );
    if (requestId !== latestRequestRef.current) {
      return;
    }
    setAerospaceSpaces(spaces.flat());
  }, [displays]);

  // Refreshes spaces with the data sent by simple-bar-server if it exists
  // in order to speed up the process then refreshes everything in background
  // else, simply refreshes everything
  const refreshSpaces = React.useCallback(
    async (data) => {
      if (data) {
        const { space } = data;
        setAerospaceSpaces((current) => {
          return current.map((s) => ({ ...s, focused: s.workspace === space }));
        });
        getSpaces();
      } else {
        await getSpaces();
      }
    },
    [getSpaces]
  );

  // Resets the aerospace spaces state
  const resetSpaces = () => {
    setAerospaceSpaces([]);
  };

  // Use server socket to fetch and reset spaces
  useServerSocket("spaces", serverEnabled, refreshSpaces, resetSpaces);

  // Fetch spaces on component mount and when displayIndex changes
  React.useEffect(() => {
    refreshSpaces();
  }, [refreshSpaces, displayIndex]);

  return (
    <AerospaceContext.Provider value={{ spaces: aerospaceSpaces }}>
      {children}
    </AerospaceContext.Provider>
  );
}