configuring workspacer
use workspacer like a pro!
Workspacer is configured with the C# programming language. The expressiveness of C# allows you to be hyper-specific in terms of describing your desired behavior. This configuration documentation assumes that you have already created the example config in the correct folder, if you haven’t, check the quick-start guide.
I don’t know C#, or how to code, should I use workspacer?
Workspacer is intended to be on the extreme end of the power user spectrum. You can use workspacer without knowing how to code, but advanced configuration will be challenging if you need to deviate outside of the examples and configurations of other users.
How do I define custom workspaces?
Workspaces are created by calling the appropriate function on the IWorkspaceContainer
you are using. In the default configuration, that is CreateWorkspace
on the context.WorkspaceContainer
object. For example:
context.WorkspaceContainer.CreateWorkspace("workspace");
context.WorkspaceContainer.CreateWorkspace("another");
context.WorkspaceContainer.CreateWorkspaces("more", "than", "one");
Layout Engines
Layout engines define the way windows get arranged on each workspace. There are a number of different ways to lay out windows and you can swap between them dynamically. By default, workspacer loads two engines to switch between, the FullLayoutEngine
and the TallLayoutEngine
, however you can change the set of default layout engines via:
context.DefaultLayouts = () => new ILayoutEngine[] { new FullLayoutEngine() };
You can even manually specify the layout engines on a per-workspace basis, by passing the different layout engines to the CreateWorkspace
(or equivalent) function:
context.WorkspaceContainer.CreateWorkspace("layouts!", new FullLayoutEngine(), new TallLayoutEngine());
Existing Layout Engines
FullLayoutEngine
- Maximizes the current focused window and hides all others.
TallLayoutEngine
- Splits the screen in two horizontal zones, a primary and a secondary one.
- Windows get created in the secondary zone by default.
- The number of windows in the primary zone can be dynamically adjusted.
PaneLayoutEngine
- The
PaneLayoutEngine
is an abstract class with two implementations: theVertLayoutEngine
and theHorzLayoutEngine
. - The
VertLayoutEngine
aligns windows in columns, theHorzLayoutEngine
in rows.
- The
DwindleLayoutEngine
- Uses primary and secondary zones as the TallLayoutEngine.
- Tiles windows in a
left-right-bottom-left-up-right-bottom-left-up
order.
In development
GridLayoutEngine
- Creates a dynamic (NxN) grid in which windows are sorted.
- Requires support for on-the-fly change in row and column numbers.
Filters & Routes
By default, workspacer will ignore certain system windows, such as Task Manager and workspacer itself, and will route windows to the focused workspace when they are opened. This is completely customizable via IWindowRouter
.
The default configuration provides the standard set of ignore/routing rules, but more can be added via calls to AddFilter
and AddRoute
.
# custom filter
context.WindowRouter.AddFilter((window) => !window.Title.Contains("my fun application"));
# custom route
context.WindowRouter.AddRoute((window) => window.Title.Contains("Google Chrome") ? context.WorkspaceContainer["web"] : null);
The AddFilter
call will ensure that any window title containing the text "my fun application"
will be ignored by workspacer. A true
return value will allow the window to be managed, while a false
value will force workspacer to ignore the window. This is recommended for full-screen applications such as videogames which may have conflicts with workspacer that could lead to unwanted crashes or false detections from an anti-cheat system due to workspacer trying to manage it.
The AddRoute
call will ensure that any window title containing the text “Google Chrome” will be automatically placed in the “web” workspace. A null
return value will signal to workspacer that the next route should be checked, while returning an actual workspace will ensure that the workspace manager will place the window in the returned workspace.
Plugins
Workspacer offers additional functionality beyond just tiling your windows through Plugins. This is a way for a developer to ship functionality as a DLL that taps into workspacer without requiring massive amounts of extra code in your config file. Supported plugins include:
- Menu Bar
- The workspacer bar creates a nix-like top-bar which shows the list of workspaces and other useful information.
- Widgets allow for further the customisation of the bar, look at the menu bar section for details.
- Action Menu
- The action menu allows the user to create custom (nested) menus which can call any function or shortcuts you’d like.
- Focus Indicator
- Draws a border around the current focused window. Border width and color can be adjusted through attributes see Focus Indicator Config.
- Gaps
- Allows for user-configurable gaps between windows.
- Similar to i3 these gaps are seperated into an ‘inner’ and an ‘outer gap’.
- Currently gap settings are global i.e. affect all workspaces, a local option can be implemented.
- Title bar
- Allows for the removal of the title bar from windows
Most plugins can be configured using either an Action
to change the default configuration, or by passing a configuration directly. For instance, the menu bar plugin may be configured in either of the following two ways:
context.AddBar(new BarPluginConfig()
{
FontName = "JetBrainsMono NF",
});
context.AddBar(context =>
{
context.FontName = "JetBrainsMono NF";
});
In the examples below, the top method is used, as it explicitly states the type of the configuration (in this case BarPluginConfig
).
Menu Bar
Like other tiling window managers workspacer includes a status/menu bar which shows relevant information to improve your workflow, for example: showing your workspaces, your battery level and the time. It can also have additional features provided through custom widgets by creating a class which inherits from BarWidgetBase.
The bar can be installed like this:
context.AddBar(new BarPluginConfig());
The default workspacer config will do this for you automatically, so the only thing you will likely need to change is the set of widgets installed via the LeftWidgets
and RightWidgets
properties on the config
optional parameter.
An example of a bar, which implements the TimeWidget
with a custom time format and the BatteryWidget
is shown below:
context.AddBar(new BarPluginConfig()
{
BarTitle = "workspacer.Bar",
FontSize = 14,
FontName = "JetBrainsMono NF",
RightWidgets = () => new IBarWidget[] { new TimeWidget(1000,"hh:mm"), new BatteryWidget() },
});
All widgets output a string and share common properties as defined by the IBarWidgetPart
interface.
public interface IBarWidgetPart
{
string Text { get; }
Color ForegroundColor { get; }
Color BackgroundColor { get; }
Action PartClicked { get; }
string FontName { get; }
}
Widgets support custom on-click functions and callbacks through the PartClicked
Action. Icon fonts are also supported and can be set for individual widgets but require system wide installation of the font and there may be issues with .OTF
files, so TTF
s are recommended. To add icons to a widget you must use its unicode value.
For example if you wanted to add this monitor icon from FontAwesome you would have to write "\uf108"
.
Menu Bar Widgets
ActiveLayoutWidget
- Shows the name of the current active window layout engine.
BatteryWidget
- For mobile devices/laptops only.
- Shows the current battery charge percentage.
- Text color can be adjusted based on rules using the
ChargeColor
andChargeTreshold
attributes, seeBatteryWidget
for details.
TimeWidget
- A customisable widget to show the time with standard C# datetime formatting.
TitleWidget
- Shows the title of windows in the current workspace.
- Showing all window titles instead of only the focused one can be configured with
ShowAllWindowTitles
. - Users can select to show just the name of the program instead of the full window title by using
isShortTitle
flag. - More configuration details are available here.
WorkspaceWidget
- Shows all existing workspaces.
- Allows for significant customisation:
- Change the text color of the workspace name depending on it’s state (focused, empty).
- Supports blinking for events and notifications.
- Further details here.
TextWidget
- Shows provided fixed text.
- Useful for dividers.
CpuPerformanceWidget
- Shows percentage of processor usage.
- Reports specific core when ProcessorCore is set.
- When clicked, Task Manager is opened.
- Further details here.
MemoryPerformanceWidget
- Shows percentage of memory usage.
- When clicked, Task Manager is opened.
- Further details here.
NetworkPerformanceWidget
- Shows the total of trafic on a specific network interface.
- When clicked, Network Connections is opened.
- Further details here.
The Action Menu
The action menu is implemented as a plugin
, (see the above Plugins section). The action menu can be installed like this:
var actionMenu = context.AddActionMenu();
actionMenu.DefaultMenu.AddMenu("do a thing", () => DoACoolThing());
actionMenu.DefaultMenu.AddMenu("open a menu", () => CreateAMenu(container, actionMenu));
actionMenu.DefaultMenu.AddFreeForm("write to console", (s) => Console.WriteLine(s));
Note that DefaultMenu
contains a useful set of default items. If you don’t want these defaults, or you want to create a menu for nesting, you can use the Clear
method. You can nest these menus as much as desired, so any set of menus can be created.
Gaps
Gaps are supported through IConfigContext::AddLayoutProxy
which is also used to recalculate window positions when the menu bar is present.
They can be implemented like this:
#r "C:\Program Files\workspacer\plugins\workspacer.Gap\workspacer.Gap.dll"
using workspacer.Gap;
var gap = 20;
context.AddGap(
new GapPluginConfig()
{
InnerGap = gap,
OuterGap = gap / 2,
Delta = gap / 2,
}
);
Gaps can be also adjusted on-the-fly by binding the relevant functions (e.g. IncrementOuterGap
, DecrementInnerGap
) to keybinds.
For more details have a look at an example from the user snippets
Title Bar
This adds the ability to remove the title bar from specific or all windows. This is useful for applications that have a title bar which is unncessary for the purpose of the window when Workspacer is in use.
By default, the title bar and sizing border are shown on all windows. To update the defaults:
#r "C:\Program Files\workspacer\plugins\workspacer.TitleBar\workspacer.TitleBar.dll"
using workspacer.TitleBar;
var titleBarPluginConfig = new TitleBarPluginConfig(new TitleBarStyle(showTitleBar: false, showSizingBorder: false));
context.AddTitleBar(titleBarPluginConfig);
The available styles can be seen below:
To customize the styling for specific windows:
var titleBarPluginConfig = new TitleBarPluginConfig();
titleBarPluginConfig.SetWindowProcessName("Notepad", new TitleBarStyle(showTitleBar: false, showSizingBorder: false));
context.AddTitleBar(titleBarPluginConfig);
Setting the filters can be done using the TitleBarPluginConfig
methods:
public void SetWindowClass(string windowClass, TitleBarStyle style);
public void SetWindowProcessName(string processName, TitleBarStyle style);
public void SetWindowTitle(string title, TitleBarStyle style);
public void SetWindowTitleMAtch(string match, TitleBarStyle style);
How do I register custom keybindings?
Workspacer subscribes to the default set of key bindings automatically for you. If you want to add additional key bindings, or override an existing one, you can do the following:
Define the mod key. Check KeyModifiers.cs to see all available modifiers. KeyModifiers.Alt
is the default mod key. If you want to use multiple modifier keys (e.g. Left Alt + Left Control), use KeyModifiers.LAlt | KeyModifiers.LCtrl
.
KeyModifiers mod = KeyModifiers.Alt;
Add a key binding using context.Keybinds.Subscribe
. See Keys.cs for all the available key names.
context.Keybinds.Subscribe(mod, Keys.Y, () => Console.WriteLine("Y was pressed"))
If you want to remove a keybinding that already exists, you can unsubscribe from it:
context.Keybinds.Unsubscribe(mod, Keys.Y);
Finally, you can remove all the default keybindings via:
context.Keybinds.UnsubscribeAll();
How do I minimize windows?
By default, context.CanMinimizeWindows = false
. To enable the minimizing of windows, set:
context.CanMinimizeWindows = true;
How do I change .workspacer configuration folder location?
By default, the .workspacer is located at your userprofile folder, but we can set a UserEnvironmentVariable called “WORKSPACER_CONFIG” to change this location. If the UserEnvironmentVariable exists it will create a folder inside the path that the variable is referencing in and it will use the configuration files inside a %WORKSPACER_CONFIG%/.config/workspacer folder. It will create this path if it doesn’t exist.
How can I troubleshoot Visual Studio Code type checking?
Visual Studio Code uses OmniSharp to provide intellisense and syntax interpolation of C# script files
such as your workspacer.config.csx
- this should work provided you have the C# extension installed.
However, issues with completion or problems indicated for valid code arise when OmniSharp finds multiple .NET SDKs
installed. Each framework is (.NET Framework, .NET Core, .NET etc) a candidate for the backend it uses to understand your .csx
file.
One way to confirm this is by viewing OmniSharp’s output in Output > OmniSharp Log
after loading workspace.config.csx
.
For example:
[info]: OmniSharp.Script.ScriptContextProvider
Searching for compilation dependencies with the fallback framework of 'net461'.
OmniSharp will display the default framework it has chosen which in this case is .NET Framework 4.6.1
on the system
instead of the correct .NET
. This framework does not understand the lambda expressions we use in config,
so the following problem is found for the default template (workspacer.config.template.csx
):
Cannot convert lambda expression to type 'Action<IConfigContext>' because it is not a delegate type [workspacer.config.csx] csharp(CS1660)
Workarounds
In the case you don’t require multiple .NET
runtimes on your machine, simply uninstall SDKs so that the only SDK
installed matches the latest one targeted by workspacer
.
Reload VS Code and confirm Output > OmniSharp Log
displays the right target framework and no false problems appear.
In the case that multiple frameworks are required, there is also the option of specifying which one OmniSharp should use:
-
Create an
omnisharp.json
file in%USERS%/.workspacer
(yourworkspacer.config.csx
should also live here) -
Add this sample config for
.NET 5
(which is targeted at time of writing) to the file:{ "script": { "enabled": true, "defaultTargetFramework": "net7.0", "enableScriptNuGetReferences": true } }
-
Reload VS Code and confirm
Output > OmniSharp Log
displays the right target framework and no false problems appear.