Skip to content

Commit

Permalink
feat: add komorebi provider (#32)
Browse files Browse the repository at this point in the history
  • Loading branch information
lars-berger authored Feb 29, 2024
1 parent 6742fa0 commit f712189
Show file tree
Hide file tree
Showing 22 changed files with 1,196 additions and 48 deletions.
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pnpm-lock.yaml
packages/desktop/installer.wxs
README.md
46 changes: 46 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,52 @@ window_rules:
match_process_name: '/Zebar/'
```
## ➡️ Usage with Komorebi
Modify the `float_rules` in the Komorebi config options (at `%userprofile%/komorebi.json`).

```json
{
"float_rules": [
{
"kind": "Exe",
"id": "Zebar.exe",
"matching_strategy": "Equals"
}
]
}
```

And in the Zebar config (if using the default generated one), replace the GlazeWM element with the following:

```yaml
template/workspaces:
styles: |
display: flex;
align-items: center;
.workspace {
background: rgba(255, 255, 255, 0.05);
margin-right: 4px;
width: 30px;
height: 30px;
color: #ffffffe6;
border: none;
border-radius: 2px;
&.active {
background: rgba(255, 255, 255, 0.1);
}
}
providers: ['glazewm']
template: |
@for (workspace of komorebi.currentWorkspaces) {
<button class="workspace {{ workspace === komorebi.focusedWorkspace && 'active' }}">
{{ workspace.name }}
</button>
}
```

## 🌟 Intro to Zebar

There's 3 big differences that set Zebar apart from other similar projects:
Expand Down
3 changes: 3 additions & 0 deletions packages/client-api/src/providers/create-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { createDateProvider } from './date/create-date-provider';
import { createGlazewmProvider } from './glazewm/create-glazewm-provider';
import { createHostProvider } from './host/create-host-provider';
import { createIpProvider } from './ip/create-ip-provider';
import { createKomorebiProvider } from './komorebi/create-komorebi-provider';
import { createMemoryProvider } from './memory/create-memory-provider';
import { createMonitorsProvider } from './monitors/create-monitors-provider';
import { createNetworkProvider } from './network/create-network-provider';
Expand Down Expand Up @@ -36,6 +37,8 @@ export async function createProvider(
return createHostProvider(config, owner);
case ProviderType.IP:
return createIpProvider(config, owner);
case ProviderType.KOMOREBI:
return createKomorebiProvider(config, owner);
case ProviderType.MEMORY:
return createMemoryProvider(config, owner);
case ProviderType.MONITORS:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { GwmClient, GwmEventType, type Workspace } from 'glazewm';

import { getMonitors } from '~/desktop';
import type { GlazewmProviderConfig } from '~/user-config';
import { getCoordinateDistance } from '~/utils';

export async function createGlazewmProvider(
_: GlazewmProviderConfig,
Expand Down Expand Up @@ -37,23 +38,15 @@ export async function createGlazewmProvider(

// Get GlazeWM monitor that corresponds to the bar's monitor.
const monitor = monitors.reduce((a, b) =>
getDistance(currentPosition, a) < getDistance(currentPosition, b)
getCoordinateDistance(currentPosition, a) <
getCoordinateDistance(currentPosition, b)
? a
: b,
);

setGlazewmVariables({ workspacesOnMonitor: monitor.children });
}

function getDistance(
pointA: { x: number; y: number },
pointB: { x: number; y: number },
) {
return Math.sqrt(
Math.pow(pointB.x - pointA.x, 2) + Math.pow(pointB.y - pointA.y, 2),
);
}

return {
get workspacesOnMonitor() {
return glazewmVariables.workspacesOnMonitor;
Expand Down
191 changes: 191 additions & 0 deletions packages/client-api/src/providers/komorebi/create-komorebi-provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
import { createEffect, type Owner } from 'solid-js';
import { createStore } from 'solid-js/store';

import type { KomorebiProviderConfig } from '~/user-config';
import { createProviderListener } from '../create-provider-listener';
import { getMonitors } from '~/desktop';
import { getCoordinateDistance } from '~/utils';

interface KomorebiResponse {
allMonitors: KomorebiMonitor[];
focusedMonitorIndex: number;
}

export interface KomorebiProvider {
/**
* Workspace displayed on the current monitor.
*/
displayedWorkspace: KomorebiWorkspace;

/**
* Workspace that currently has focus (on any monitor).
*/
focusedWorkspace: KomorebiWorkspace;

/**
* Workspaces on the current monitor.
*/
currentWorkspaces: KomorebiWorkspace[];

/**
* Workspaces across all monitors.
*/
allWorkspaces: KomorebiWorkspace[];

/**
* All monitors.
*/
allMonitors: KomorebiMonitor[];

/**
* Monitor that currently has focus.
*/
focusedMonitor: KomorebiMonitor;

/**
* Monitor that is nearest to this Zebar window.
*/
currentMonitor: KomorebiMonitor;
}

export interface KomorebiMonitor {
id: number;
deviceId: string;
focusedWorkspaceIndex: number;
name: string;
size: KomorebiRect;
workAreaOffset: number | null;
workAreaSize: KomorebiRect;
workspaces: KomorebiWorkspace[];
}

export interface KomorebiWorkspace {
containerPadding: number | null;
floatingWindows: KomorebiWindow[];
focusedContainerIndex: number;
latestLayout: KomorebiRect[];
layout: KomorebiLayout;
layoutFlip: KomorebiLayoutFlip | null;
maximizedWindow: KomorebiWindow | null;
monocleContainer: KomorebiContainer | null;
name: string | null;
tilingContainers: KomorebiContainer[];
workspacePadding: number | null;
}

export interface KomorebiContainer {
id: string;
windows: KomorebiWindow[];
}

export interface KomorebiWindow {
class: string | null;
exe: string | null;
hwnd: number;
title: string | null;
}

export interface KomorebiRect {
left: number;
top: number;
right: number;
bottom: number;
}

export type KomorebiLayout =
| 'bsp'
| 'vertical_stack'
| 'horizontal_stack'
| 'ultrawide_vertical_stack'
| 'rows'
| 'grid'
| 'custom';

export type KomorebiLayoutFlip =
| 'horizontal'
| 'vertical'
| 'horizontal_and_vertical';

export async function createKomorebiProvider(
config: KomorebiProviderConfig,
owner: Owner,
): Promise<KomorebiProvider> {
const { currentMonitor } = await getMonitors();

const providerListener = await createProviderListener<
KomorebiProviderConfig,
KomorebiResponse
>(config, owner);

const [komorebiVariables, setKomorebiVariables] = createStore(
await getVariables(),
);

createEffect(async () => setKomorebiVariables(await getVariables()));

async function getVariables() {
const state = providerListener();
const currentPosition = { x: currentMonitor!.x, y: currentMonitor!.y };

// Get Komorebi monitor that corresponds to the window's monitor.
const currentKomorebiMonitor = state.allMonitors.reduce((a, b) =>
getCoordinateDistance(currentPosition, {
x: a.workAreaSize.left,
y: a.workAreaSize.top,
}) <
getCoordinateDistance(currentPosition, {
x: b.workAreaSize.left,
y: b.workAreaSize.top,
})
? a
: b,
);

const displayedWorkspace =
currentKomorebiMonitor.workspaces[
currentKomorebiMonitor.focusedWorkspaceIndex
]!;

const allWorkspaces = state.allMonitors.flatMap(
monitor => monitor.workspaces,
);

const focusedMonitor = state.allMonitors[state.focusedMonitorIndex]!;
const focusedWorkspace =
focusedMonitor.workspaces[focusedMonitor.focusedWorkspaceIndex]!;

return {
displayedWorkspace,
focusedWorkspace,
currentWorkspaces: currentKomorebiMonitor.workspaces,
allWorkspaces,
focusedMonitor,
currentMonitor: currentKomorebiMonitor,
allMonitors: state.allMonitors,
};
}

return {
get displayedWorkspace() {
return komorebiVariables.displayedWorkspace;
},
get focusedWorkspace() {
return komorebiVariables.focusedWorkspace;
},
get currentWorkspaces() {
return komorebiVariables.currentWorkspaces;
},
get allWorkspaces() {
return komorebiVariables.allWorkspaces;
},
get allMonitors() {
return komorebiVariables.allMonitors;
},
get focusedMonitor() {
return komorebiVariables.focusedMonitor;
},
get currentMonitor() {
return komorebiVariables.currentMonitor;
},
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
GlazewmProviderConfigSchema,
HostProviderConfigSchema,
IpProviderConfigSchema,
KomorebiProviderConfigSchema,
MemoryProviderConfigSchema,
MonitorsProviderConfigSchema,
NetworkProviderConfigSchema,
Expand All @@ -22,6 +23,7 @@ export const ProviderConfigSchema = z.union([
GlazewmProviderConfigSchema,
HostProviderConfigSchema,
IpProviderConfigSchema,
KomorebiProviderConfigSchema,
MemoryProviderConfigSchema,
MonitorsProviderConfigSchema,
NetworkProviderConfigSchema,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export enum ProviderType {
GLAZEWM = 'glazewm',
HOST = 'host',
IP = 'ip',
KOMOREBI = 'komorebi',
MEMORY = 'memory',
MONITORS = 'monitors',
NETWORK = 'network',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export * from './date-provider-config.model';
export * from './glazewm-provider-config.model';
export * from './host-provider-config.model';
export * from './ip-provider-config.model';
export * from './komorebi-provider-config.model';
export * from './memory-provider-config.model';
export * from './monitors-provider-config.model';
export * from './network-provider-config.model';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { z } from 'zod';

import { ProviderType } from '../provider-type.model';

export const KomorebiProviderConfigSchema = z.object({
type: z.literal(ProviderType.KOMOREBI),
});

export type KomorebiProviderConfig = z.infer<
typeof KomorebiProviderConfigSchema
>;
11 changes: 11 additions & 0 deletions packages/client-api/src/utils/get-coordinate-distance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* Get distance between two points.
*/
export function getCoordinateDistance(
pointA: { x: number; y: number },
pointB: { x: number; y: number },
) {
return Math.sqrt(
Math.pow(pointB.x - pointA.x, 2) + Math.pow(pointB.y - pointA.y, 2),
);
}
1 change: 1 addition & 0 deletions packages/client-api/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ export * from './clsx';
export * from './create-getter-proxy';
export * from './create-logger';
export * from './create-string-scanner';
export * from './get-coordinate-distance';
export * from './simple-hash';
export * from './to-css-selector';
Loading

0 comments on commit f712189

Please sign in to comment.