Whim
Whim copied to clipboard
IPC
Whim will transition to an IPC message-passing model for plugins. This will enable the following scenarios:
- External plugins to Whim
- Whim plugins to avoid congesting the main Whim thread when handling events
IPC will occur using name pipes.
Tasks
- [ ] Add
Transformserialization and deserialization - [ ] Add
Pickerserialization and deserialization - [ ] Add
Commandserialization and deserialization - [ ] Add
NamedPipeclient and server classes - [ ] Add event emitter to
NamedPipeserver
Plugins
- [ ] Move
Whim.FocusIndicatorto a new STA - [ ] Move
Whim.Barto a new STA - [ ] Move
Whim.CommandPaletteto a new STA - [ ] Move
Whim.FloatingLayoutto a new STA - [ ] Move
Whim.Gapsto a new STA - [ ] Move
Whim.LayoutPreviewto a new STA - [ ] Move
Whim.SliceLayoutto a new STA - [ ] Move
Whim.TreeLayoutto a new STA - [ ] Move
Whim.TreeLayout.Barto a new STA - [ ] Move
Whim.TreeLayout.CommandPaletteto a new STA - [ ] Move
Whim.Updaterto a new STA
On the topic of commands, I think we can benefit from allowing commands to accept parameters and return results. As is, they're just invoked nominally. Works fine, but leads to awkward workarounds like this:
// Set up workspaces.
const int numWorkspaces = 12;
for(var i = 1; i <= numWorkspaces; i++) {
context.WorkspaceManager.Add($"{i}");
if(i > 10) {
continue;
}
var vk = VIRTUAL_KEY.VK_0 + (ushort)(i%10);
var idx = i;
context.KeybindManager.SetKeybind(
$"whim.core.activate_workspace_{idx}",
new Keybind(IKeybind.Win, vk));
context.CommandManager.Add($"move_window_to_workspace_{idx}", $"Move window to workspace {idx}",
() => {
var workspaces = context.WorkspaceManager.ToArray();
context.WorkspaceManager.MoveWindowToWorkspace(workspaces[idx-1]);
});
context.KeybindManager.SetKeybind(
$"whim.custom.move_window_to_workspace_{idx}",
new Keybind(IKeybind.WinShift, vk));
}
for(var i = 11; i <= numWorkspaces; i++) {
var idx = i;
context.CommandManager.Add($"activate_workspace_{idx}", $"Activate workspace {idx}",
() => {
var workspaces = context.WorkspaceManager.ToArray();
context.WorkspaceManager.Activate(workspaces[idx-1]);
});
context.CommandManager.Add($"move_window_to_workspace_{idx}", $"Move window to workspace {idx}",
() => {
var workspaces = context.WorkspaceManager.ToArray();
context.WorkspaceManager.MoveWindowToWorkspace(workspaces[idx-1]);
});
}
context.KeybindManager.SetKeybind("whim.custom.activate_workspace_11",
new Keybind(IKeybind.Win, VIRTUAL_KEY.VK_OEM_7)); // quote
context.KeybindManager.SetKeybind("whim.custom.move_window_to_workspace_11",
new Keybind(IKeybind.WinShift, VIRTUAL_KEY.VK_OEM_7)); // quote
context.KeybindManager.SetKeybind("whim.custom.activate_workspace_12",
new Keybind(IKeybind.Win, VIRTUAL_KEY.VK_OEM_5)); // backslash
context.KeybindManager.SetKeybind("whim.custom.move_window_to_workspace_12",
new Keybind(IKeybind.WinShift, VIRTUAL_KEY.VK_OEM_5)); // backslash
Not a showstopper, but if Whim introduces IPC, I think it'd be easier to rethink how Commands work before IPC/RPC implementation.
Question: can/should the IPC be implemented as a plugin? My brain kinda sees it as a binding to the CommandManager. So a plugin could take care of marshalling bytes in and out of the process and just glue it to the ICommandManager methods.
Question: can/should the IPC be implemented as a plugin? My brain kinda sees it as a binding to the CommandManager. So a plugin could take care of marshalling bytes in and out of the process and just glue it to the ICommandManager methods.
I think we're reasoning along a similar line. My loose initial idea was that the plugin would:
- expose the existing commands to perform actions
- support a new type of command (command request?) to retrieve data
- support another new type of command which would accept arguments
I was leaning towards having the new commands being specific to the plugin where they wouldn't be a formal part of the core commands interface, but perhaps there's a case for having them in the core.
Another thing I haven't thought through at all is what sort of IPC would be used (named pipes, TCP, web sockets, gRPC, SignalR).